c++ - 模板类对象数组
问题描述
问题
我想要一个指向模板类实例的指针数组。如果 C++ 允许在基类中使用模板化的虚拟方法以及模板化的派生类,我的问题将得到解决。
因此,如何实现模板化的虚拟方法?
下面我有一个似乎可行的解决方案,但我对有关我的实现的评论感兴趣。
约束
模板参数是无限可变的,例如,我不能枚举这个模板类的每一个特化。模板类T
可以是任何 POD、POD 数组或 POD 结构。
完整的集合T
在编译时是已知的。基本上,我有一个文件,它定义了T
用于实例化对象的所有不同对象,并使用 Xmacros ( https://en.wikipedia.org/wiki/X_Macro ) 创建对象数组。
我知道这不是个好主意。让我们暂时忽略它。这最终更像是一种好奇心。
可能的解决方案
这些是我研究过的东西。
创建基类和派生类
class Base {
virtual void SomeMethod() = 0;
}
template <class T>
class Derived : Base {
void SomeMethod() {...}
}
问题是我无法声明所有Base
要重载的虚拟方法,因为无法对虚拟方法进行模板化。否则,这将是一个完美的解决方案。
std::any/std::variant
我使用的是 C++17,所以我可以定义采用std::any
. 但它不能保存数组,这妨碍了它在这里的使用。
CRTP
似乎这无助于我创建这些不同对象的数组。我需要做类似的事情
template <typename D, typename T>
class Base
{
...
};
template <typename T>
class Derived : public Base<Derived, T>
{
...
};
所以我最终还是试图创建一个Derived<T>
对象数组。
访客模式
再次看起来我需要枚举Visitable
类需要服务的每种可能的类型,虽然并非不可能(同样,我有一个文件定义了T
将使用的所有不同的文件)似乎更多的 Xmacros,这只是使问题更复杂。
我的解决方案
这就是我想出的。它将在https://www.onlinegdb.com/online_c++_compiler中运行
#include <iostream>
#include <array>
#include <typeinfo>
// Base class which declares "overloaded" methods without implementation
class Base {
public:
template <class T>
void Set(T inval);
template <class T>
void Get(T* retval);
virtual void Print() = 0;
};
// Template class which implements the overloaded methods
template <class T>
class Derived : public Base {
public:
void Set(T inval) {
storage = inval;
}
void Get(T* retval) {
*retval = storage;
}
void Print() {
std::cout << "This variable is type " << typeid(T).name() <<
", value: " << storage << std::endl;
}
private:
T storage = {};
};
// Manually pointing base overloads to template methods
template <class T> void Base::Set(T inval) {
static_cast<Derived<T>*>(this)->Set(inval);
}
template <class T> void Base::Get(T* retval) {
std::cout << "CALLED THROUGH BASE!" << std::endl;
static_cast<Derived<T>*>(this)->Get(retval);
}
int main()
{
// Two new objects
Derived<int>* ptr_int = new Derived<int>();
Derived<double>* ptr_dbl = new Derived<double>();
// Base pointer array
std::array<Base*, 2> ptr_arr;
ptr_arr[0] = ptr_int;
ptr_arr[1] = ptr_dbl;
// Load values into objects through calls to Base methods
ptr_arr[0]->Set(3);
ptr_arr[1]->Set(3.14);
// Call true virtual Print() method
for (auto& ptr : ptr_arr) ptr->Print();
// Read out the values
int var_int;
double var_dbl;
std::cout << "First calling Get() method through true pointer." << std::endl;
ptr_int->Get(&var_int);
ptr_dbl->Get(&var_dbl);
std::cout << "Direct values: " << var_int << ", " << var_dbl << std::endl;
std::cout << "Now calling Get() method through base pointer." << std::endl;
ptr_arr[0]->Get(&var_int);
ptr_arr[1]->Get(&var_dbl);
std::cout << "Base values: " << var_int << ", " << var_dbl << std::endl;
return 0;
}
当它运行时,它表明调用Base
正确的方法指向Derived
实现。
This variable is type i, value: 3
This variable is type d, value: 3.14
First calling Get() method through true pointer.
Direct values: 3, 3.14
Now calling Get() method through base pointer.
CALLED THROUGH BASE!
CALLED THROUGH BASE!
Base values: 3, 3.14
本质上我是手动创建虚拟方法指针。但是,由于我明确这样做,我可以使用模板方法,Base
其中指向Derived
. 它更容易出错,例如对于每个模板方法,我需要输入两次方法名称,即,我可能会搞砸:
template <class T> void Base::BLAH_SOMETHING(T inval) {
static_cast<Derived<T>*>(this)->WHOOPS_WRONG_CALL(inval);
}
那么,在这一切之后,这是一个可怕的想法吗?对我来说,它似乎实现了我规避模板化虚拟方法限制的目标。这真的有什么问题吗?我知道可能有一些方法来构造代码,这一切都变得不必要了,我只关注这个特定的构造。
解决方案
它更容易出错,例如对于每个模板方法,我需要输入两次方法名称
哦,这是你最不关心的问题。想象一下,如果您选择了错误的类型。
至少让自己头疼并使用dynamic_cast
:
class Base {
public:
virtual ~Base() = default;
template <class T>
void Set(T inval) {
dynamic_cast<Derived<T>&>(*this).Set(inval);
}
template <class T>
T Get() {
return dynamic_cast<Derived<T>&>(*this).Get();
}
};
template <class T>
class Derived : public Base {
public:
void Set(T inval) {
storage = inval;
}
T Get() {
return storage;
}
private:
T storage{};
};
除此之外,我同意这些评论,这可能不是解决您问题的正确方法。
推荐阅读
- python - 为什么我的区域提案网络 (RPN) 输出 4d 预测/分数数组,我如何解释输出?
- python - Dill/Marshal 反序列化后的 NameError
- java - 消息删除功能可删除文本、pdf、图像、mp3 文件消息等
- visual-studio-code - sudo 命令在 Vscode 终端中不起作用
- python - 在张量的上下文中理解广播
- .net-core - 动态查询中的 IgonreFilter
- python - html、flask 中的元素使用
- vb.net - 为什么 Me.Controls.OfType 在 VB.NET 中不起作用?
- swift - 将 CollectionView 图像的更新顺序保存到 UserDefaults - Swift
- python - 使用 ImageDataGenerator 进行迁移学习时出现形状不兼容错误