jte*_*dit 40 c++ templates stdvector
我需要在一个向量中存储多种类型的模板类.
例如,对于:
template <typename T>
class templateClass{
bool someFunction();
};
Run Code Online (Sandbox Code Playgroud)
我需要一个存储所有的向量:
templateClass<int> t1;
templateClass<char> t2;
templateClass<std::string> t3;
etc
Run Code Online (Sandbox Code Playgroud)
据我所知这是不可能的,如果有人可以说怎么样?
如果不可能有人解释如何进行以下工作?
作为一种解决方法,我尝试使用基本的非模板类并从中继承模板类.
class templateInterface{
virtual bool someFunction() = 0;
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction();
};
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个向量来存储基础"templateInterface"类:
std::vector<templateInterface> v;
templateClass<int> t;
v.push_back(t);
Run Code Online (Sandbox Code Playgroud)
这产生了以下错误:
error: cannot allocate an object of abstract type 'templateInterface'
note: because the following virtual functions are pure within 'templateInterface'
note: virtual bool templateInterface::someFunction()
Run Code Online (Sandbox Code Playgroud)
为了解决这个错误,我在templateInterface中使函数不是一个纯虚拟的,通过提供一个函数体,这个编译但是在调用函数时不使用overide,而是在虚函数中使用body.
例如:
class templateInterface{
virtual bool someFunction() {return true;}
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction() {return false;}
};
std::vector<templateInterface> v;
templateClass<int> i;
v.push_back(i);
v[0].someFunction(); //This returns true, and does not use the code in the 'templateClass' function body
Run Code Online (Sandbox Code Playgroud)
有没有办法解决这个问题,以便使用重写的函数,还是有另一种解决方法可以在一个向量中存储多个模板类型?
lee*_*mes 28
为什么你的代码不起作用:
在值上调用虚函数不使用多态.它调用的函数是为编译器看到的这个精确符号的类型定义的,而不是运行时类型.将子类型插入基类型的向量时,您的值将转换为基类型("类型切片"),这不是您想要的.对它们调用函数现在将调用为基类型定义的函数,因为它不是那种类型.
如何解决这个问题?
使用此代码段可以重现同样的问题:
templateInterface x = templateClass<int>(); // Type slicing takes place!
x.someFunction(); // -> templateInterface::someFunction() is called!
Run Code Online (Sandbox Code Playgroud)
多态性仅适用于指针或引用类型.然后,它将使用指针/引用后面的对象的运行时类型来决定调用哪个实现(通过使用它的vtable).
对于类型切片,转换指针是完全"安全的".您的实际值根本不会被转换,多态性将按预期工作.
示例,类似于上面的代码片段:
templateInterface *x = new templateClass<int>(); // No type slicing takes place
x->someFunction(); // -> templateClass<int>::someFunction() is called!
delete x; // Don't forget to destroy your objects.
Run Code Online (Sandbox Code Playgroud)
矢量怎么样?
因此,您必须在代码中采用这些更改.您可以简单地将指针存储到向量中的实际类型,而不是直接存储值.
使用指针时,您还必须关心删除已分配的对象.为此,您可以使用自动关注删除的智能指针.unique_ptr是一种这样的智能指针类型.它会在超出范围时删除指针("唯一所有权" - 范围是所有者).假设您的对象的生命周期绑定到范围,这是您应该使用的:
std::vector<std::unique_ptr<templateInterface>> v;
templateClass<int> *i = new templateClass<int>(); // create new object
v.push_back(std::unique_ptr<templateInterface>(i)); // put it in the vector
v.emplace_back(new templateClass<int>()); // "direct" alternative
Run Code Online (Sandbox Code Playgroud)
然后,使用以下语法在其中一个元素上调用虚函数:
v[0]->someFunction();
Run Code Online (Sandbox Code Playgroud)
确保将所有函数设置为虚拟的,这些函数应该可以被子类覆盖.否则,将不会调用它们被覆盖的版本.但是既然你已经引入了一个"接口",我相信你正在使用抽象函数.
替代方法:
做你想做的事情的另一种方法是在向量中使用变体类型.有一些变体类型的实现,Boost.Variant是一个非常受欢迎的类型.如果您没有类型层次结构(例如存储基元类型时),此方法尤其好用.然后你会使用像这样的矢量类型std::vector<boost::variant<int, char, bool>>