【问题标题】:C++ cannot add to vector inside templateC++ 不能添加到模板内的向量
【发布时间】:2014-04-20 05:21:17
【问题描述】:

我正在学习模板。

我有:

template<typename SQLObject>
std::vector<SQLObject> executeSelectQueryReturnSQLVector(std::string _recordType,
                                                             std::string _sql,
                                                             int _rowCount)
{
    typename std::vector<SQLObject> v;

    if (_recordType == AppConstants::sSQLFieldObject)
    {
        for(int r=0; r < _rowCount; r++)
        {
            SQLFieldObject o;

            o.putFieldNumber(sqlite3_column_int(statement, 0));
            [snip]
            v.push_back(o);
        }
    }

    if (_recordType == AppConstants::sSQLNotificationObject)
    {
        for(int r=0; r < _rowCount; r++)
        {
            SQLNotificationObject o;

             o.putNotificationID(sqlite3_column_int(statement, 0));
             [snip]
             v.push_back(o);
        }
    }

    return v;
}

我在v.push_back(o); 上收到一个编译器错误,指出:

no matching member function for call to 'push_back'

我认为这是有道理的,为什么它对我来说很模糊,因为这是在编译时确定的类型名?

这是否意味着我必须实现自己的push_back() 函数?

Vandevoorde 和 Josuttis @ 2003 的“C++ 模板完整指南”是否仍然适用于 C++11?

更新 1: 考虑这个编辑:

template<typename SQLObject>
std::vector<SQLObject> executeSelectQueryReturnSQLVector(std::string _recordType,
                                                             std::string _sql,
                                                             int _rowCount)
{
    //typename std::vector<SQLObject> v;

    if (_recordType == AppConstants::sSQLFieldObject)
    {
        std::vector<SQLFieldObject> v;

        for(int r=0; r < _rowCount; r++)
        {
            SQLFieldObject o;

            o.putFieldNumber(sqlite3_column_int(statement, 0));
            [snip]
            v.push_back(o);
        }

        return v;
    }

    if (_recordType == AppConstants::sSQLNotificationObject)
    {
        std::vector<SQLNotificationObject> v;

        for(int r=0; r < _rowCount; r++)
        {
            SQLNotificationObject o;

             o.putNotificationID(sqlite3_column_int(statement, 0));
             [snip]
             v.push_back(o);
        }

        return v;
    }

    //return v;
}

return v; 都出现编译器错误,例如:

no viable conversion from 'vector<class SQLFieldObject>' to 'vector<class SQLNotificationObject>'

no viable conversion from 'vector<class SQLNotificationObject>' to 'vector<class SQLFieldObject>'

我这样称呼:

std::vector<SQLFieldObject> _v = executeSelectQueryReturnSQLVector<SQLFieldObject>    (AppConstants::sSQLFieldObject, getSQLToSelectFields(), rowCount);

std::vector<SQLNotificationObject> _v = executeSelectQueryReturnSQLVector<SQLNotificationObject>(AppConstants::sSQLNotificationObject, getSQLToSelectNotifications(), rowCount);

【问题讨论】:

  • 问题不在于模板的使用,而在于您尝试将SQLNotificationObjectSQLFieldObject 添加到SQLObject 的向量中。尝试不使用模板编写代码,你会看到同样的问题。
  • 我认为您的 SQLObject 是多态类型。在这种情况下,您需要使用指针向量,即 vector。这将允许您将 SQLFieldObject 的指针以及 SQLNotificationObject 的指针存储在同一向量中。
  • @rockoder - 我实际上调用了它两次,当被调用时它总是进入向量的相同类型。我又更新了。
  • 为了可读性,您不应将模板参数称为与实际类相同的东西(我不确定您是否正在这样做,但根据名称@看来您可能会这样做987654333@ 和 SQLFieldObject)。
  • @matt。为了安全起见,我将替换为 T。

标签: c++ templates vector compiler-errors


【解决方案1】:

v 的类型是std::vector&lt;SQLObject&gt;o 的类型是 SQLFieldObject。除非有一种自动方式将SQLFieldObject 类型的对象转换为SQLObject,否则

v.push_back(o);

这是不允许的操作。

更新

与更新代码相关的错误是:

executeSelectQueryReturnSQLVector 的返回类型是std::vector&lt;SQLObject&gt;return 语句返回 std::vector&lt;SQLFieldObject&gt;std::vector&lt;SQLNotificationObject&gt;。嗯,返回的对象的类型与函数签名中的返回类型不匹配。

更优雅地处理模板:

 // A template class that returns an appropriate string based on the
 // typename used to instantiate.
 template <typename SQLObject> struct RecordTypeChooser;

 // Specialization for returning the record type for SQLFieldObjects.
 template <> struct RecordTypeChooser<SQLFieldObject>
 {
    static std::string getRecordType() { return AppConstants::sSQLFieldObject; }
 };

 // Specialization for returning the record type for SQLNotificationObjects.
 template <> struct RecordTypeChooser<SQLNotificationObject>
 {
    static std::string getRecordType() { return AppConstants::sSQLNotificationObject; }
 };

 // A template class that constructs an object and returns it.
 // The object type is based on the typename used to instantiate.
 template <typename SQLObject> struct ObjectCreator;

 // Specialization for constructing SQLFieldObjects.
 template <> struct ObjectCreator<SQLFieldObject>
 {
    static SQLFieldObject createObject()
    {
       SQLFieldObject o;
       o.putFieldNumber(sqlite3_column_int(statement, 0));
       return o;
    }
 };

 // Specialization for constructing SQLNotificationObjects.
 template <> struct ObjectCreator<SQLNotificationObject>
 {
    static SQLNotificationObject createObject()
    {
       SQLNotificationObject o;
       o.putNotificationID(sqlite3_column_int(statement, 0));
       return o;
    }
 };



 template<typename SQLObject>
 std::vector<SQLObject> executeSelectQueryReturnSQLVector(std::string _recordType,
                                                          std::string _sql,
                                                          int _rowCount)
 {
    typename std::vector<SQLObject> v;

    // Not sure whether you need this any more.
    if (_recordType == RecordTypeChooser<SQLObject>::getRecordType())
    {
       for(int r=0; r < _rowCount; r++)
       {
          v.push_back(ObjectCreator<SQLObject>::createObject());
       }
    }

    return v;
 }

更新:完全编译和链接的源代码

 #include <vector>
 #include <string>

 struct SQLFieldObject {};
 struct SQLNotificationObject {};

 // A template class that returns an appropriate string based on the
 // typename used to instantiate.
 template <typename SQLObject> struct RecordTypeChooser;

 // Specialization for returning the record type for SQLFieldObjects.
 template <> struct RecordTypeChooser<SQLFieldObject>
 {
    static std::string getRecordType() { return "SQLFieldObject"; }
 };

 // Specialization for returning the record type for SQLNotificationObjects.
 template <> struct RecordTypeChooser<SQLNotificationObject>
 {
    static std::string getRecordType() { return "SQLNotificationObject"; }
 };

 // A template class that constructs an object and returns it.
 // The object type is based on the typename used to instantiate.
 template <typename SQLObject> struct ObjectCreator;

 // Specialization for constructing SQLFieldObjects.
 template <> struct ObjectCreator<SQLFieldObject>
 {
    static SQLFieldObject createObject()
    {
       SQLFieldObject o;
       // o.putFieldNumber(sqlite3_column_int(statement, 0));
       return o;
    }
 };

 // Specialization for constructing SQLNotificationObjects.
 template <> struct ObjectCreator<SQLNotificationObject>
 {
    static SQLNotificationObject createObject()
    {
       SQLNotificationObject o;
       // o.putNotificationID(sqlite3_column_int(statement, 0));
       return o;
    }
 };



 template<typename SQLObject>
 std::vector<SQLObject> executeSelectQueryReturnSQLVector(std::string _recordType,
                                                          std::string _sql,
                                                          int _rowCount)
 {
    typename std::vector<SQLObject> v;

    // Not sure whether you need this any more.
    if (_recordType == RecordTypeChooser<SQLObject>::getRecordType())
    {
       for(int r=0; r < _rowCount; r++)
       {
          v.push_back(ObjectCreator<SQLObject>::createObject());
       }
    }

    return v;
 }


 void foo()
 {
    std::vector<SQLFieldObject> v1 = executeSelectQueryReturnSQLVector<SQLFieldObject>("SQLFieldObject",
                                                                                       "",
                                                                                       10);

    std::vector<SQLNotificationObject> v2 = executeSelectQueryReturnSQLVector<SQLNotificationObject>("SQLNotificationObject",
                                                                                       "",
                                                                                       10);
 }

 int main() {}

【讨论】:

  • 您现在可以考虑我的描述中的更新吗?这是我最初尝试的。
  • @Jason,我更新了我的答案以解决新错误和executeSelectQueryReturnSQLVector 的重构实现,这应该不会造成更多的编译器问题。
  • 哇,让我回顾一下。我确实在template &lt;&gt; struct RecordTypeChooser&lt;SQLFieldObject&gt; 看到了一条消息:explicit specialization of 'RecordTypeChooser' in class scope 是否可以将其命名空间?
  • @Jason 我忘记将static 添加到ObjectCreator 类中的函数中。答案现已更新。
  • 我在那里添加了静态,但我仍然在template &lt;&gt; struct RecordTypeChooser&lt;SQLFieldObject&gt;template &lt;&gt; struct RecordTypeChooser&lt;SQLNotificationObject&gt;template &lt;&gt; struct ObjectCreator&lt;SQLFieldObject&gt;template &lt;&gt; struct ObjectCreator&lt;SQLNotificationObject&gt; 上看到错误,上面写着explicit specialization of 'RecordTypeChooser' in class scope template &lt;&gt; struct RecordTypeChooser&lt;SQLFieldObject&gt; 等等我提到的每个语句都不够粘贴每个错误的字符
【解决方案2】:

向量和实例中的类型不同。 Vector 仅保存原始类(否则由于内存分配问题而无法保存子类)。但是,您可以存储指向类的指针。考虑一下:

typedef boost::shared_ptr<SQLObject> SQLObjectPtr;
typedef std::vector<SQLObjectPtr> SQLObjectPtrVector;

...
for(int r=0; r < _rowCount; r++)
{
    SQLFieldObjectPtr o(new SQLFieldObject);

    ...
    v.push_back(o);
}

【讨论】:

  • 您现在可以考虑我的描述中的更新吗?这是我最初尝试的。
【解决方案3】:
#include <iostream>
#include <vector>

using namespace std;

struct A
{
    int a;
};

struct B
{
    char b;
};

template<typename T>
vector<T> fun(char type)
{
    if (type == 'A')
    {
        vector<T> v;
        // generate objects of A and append to v
        return v;
    }
    else
    {
        vector<T> v;
        // generate objects of B and append to v
        return v;
    }
}

int main()
{
    vector<A> v = fun<A>('A');

    return 0;
}

【讨论】:

  • 让我看看这个,因为它看起来与我已经在做的非常相似。让我看看我和你的区别。
猜你喜欢
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多