如何从if语句中获取类模板的实例?(C++)
How to get instance of class template out of the if statement? (C++)
假设我有一个类模板,它有一个成员pData
,它是任意类型T
的AxB
数组。
template <class T> class X{
public:
int A;
int B;
T** pData;
X(int a,int b);
~X();
void print(); //function which prints pData to screen
};
template<class T>X<T>::X(int a, int b){ //constructor
A = a;
B = b;
pData = new T*[A];
for(int i=0;i<A;i++)
pData[i]= new T[B];
//Fill pData with something of type T
}
int main(){
//...
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
if(type=="int"){
X<int> XArray(a,b);
} else if(type=="char"){
X<char> Xarray(a,b);
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray.print() //this doesn't work, as Xarray is out of scope.
}
由于实例Xarray是在if语句内部构造的,所以我不能在其他任何地方使用它。我试图在if语句之前创建一个指针,但由于当时指针的类型未知,所以没有成功。
处理这种问题的正确方法是什么?
这里的问题是X<int>
和x<char>
是完全不相关的类型。
事实上,它们都是同一个模板化类的结果,这在这里没有帮助。
我可以看到几个解决方案,但这些取决于你真正需要什么。
例如,您可以使X<>
实例派生自具有print()
方法的公共非模板基类(最终作为纯虚拟基类)。但在这样做之前,请确保它在功能级别上是有意义的:应该使用继承,因为它有意义,而不仅仅是因为技术限制。如果你这样做,你可能也会想要一个虚拟析构函数。
您也可以将std::function<void ()>
绑定并存储到要调用的方法,但要确保对象仍然"活动"(它们不在当前代码中:当它们超出范围时,X<int>
和X<char>
都会被销毁,远远早于您实际调用print()
)。
最终的解决方案是制作一些与X<int>
和X<char>
都兼容的变体类型(boost::variant<>可以在这里提供帮助)。然后,您可以编写一个访问者,为每种类型实现print()
功能。
选择最后一个解决方案,它将变成类似于:
typedef boost::variant<X<int>, X<char>> genericX;
class print_visitor : public boost::static_visitor<void>
{
public:
template <typename SomeType>
void operator()(const SomeType& x) const
{
// Your print implementation
// x is your underlying instance, either X<char> or X<int>.
// You may also make several non-templated overloads of
// this operator if you want to provide different implementations.
}
};
int main()
{
boost::optional<genericX> my_x;
if (type=="int") {
my_x = X<int>(a,b);
} else if(type=="char") {
my_x = X<char>(a,b);
}
// This calls the appropriate print.
if (my_x) {
boost::apply_visitor(print_visitor(), *my_x)
}
}
实际上,我们缺乏给出明确答案的知识:如果你的类是"实体",那么你可能应该寻求继承。如果它们更像"值类",那么变体方式可能更适合。
C++是一种静态类型语言,这意味着您必须在编译时知道对象的类型。在这种情况下,您基于用户输入构建对象的类型,因此在运行时不可能知道类型。
解决这个问题最常见的方法是使用动态多态性,其中函数是通过使用后期绑定的公共接口调用的。我们在C++中使用虚拟函数来实现这一点。例如:
struct IPrintable {
virtual void print() = 0;
};
template<class T>
class X : public IPrintable {
// Same code as you showed above.
};
int main() {
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
std::unique_ptr<IPrintable> XArray;
if(type=="int"){
XArray.reset(new X<int>(a,b));
} else if(type=="char"){
XArray.reset(new X<char>(a,b));
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray->print() // this works now!
}
这解决了范围外的问题,并允许您使用XArray变量的动态类型进行打印。虚拟功能是实现这一目标的秘密。
与其尝试将模板放入main
中,我会采取与其他建议相反的方式。。。将代码从main
的移到它自己的(可能是模板化的)函数中,该函数需要处理单个类型:
template <typename T>
void generateAndPrint(int a, int b) {
X<T> x(a,b);
x.print();
}
int main() { ...
if (type=="int") generateAndPrint<int>(a,b);
else if (type=="char") generateAndPrint<char>(a,b);
else ...
}
如果您想使用不同的数组,无论它们的类型如何,仅靠模板都无法帮助您。目前,X<int>
和X<char>
之间完全没有关系。
如果要将它们视为一个通用类型的两个子类型,则必须使用继承(以及动态分配的变量)。例如,所有X<T>
都可以继承相同的基类,比如Printable
,并且可以将数据存储在unique_ptr<Printable>
:中
unique_ptr<Printable> r;
if(type=="int"){
r.reset(new X<int>(a,b));
} else if(type=="char"){
r.reset(new X<char>(a,b);
}
r->print();
但这可能不是最好的设计。
一个可能更好的解决方案是,将所有工作转移到if内部,而不是尝试在if之外工作。在您的简单示例中,这可以通过复制对打印的调用来完成,但这也不太好。但是,朝着这个想法,我们可以创建一个模板函数来完成这项工作:
template<class T>
void workWithType(int a, int b)
{
X<T> Xarray(a, b);
Xarray.print();
}
//...
if(type=="int"){
workWithType<int>(a,b);
} else if(type=="char"){
workWithType<char>(a,b);
}
- 从C++实例化QML
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 无法创建抽象类的实例
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 我收到以下错误:抛出'std::bad_alloc'实例后终止调用
- 建议在运行时将带有类实例的列表从c++导入qml
- 约束和显式模板实例化
- 通过实例理解std::move及其目的
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 正在生成未知类实例
- 从DLL中删除类的实例
- 在std::vector上存储带有模板的类实例
- 为什么创建友元类的实例会导致"undefined reference to"错误?