异构数组中的元素可以知道它是什么模板类型吗?
Can an element in a heterogenous array know what templated type it is?
我想在一个数组中创建一大堆对象,我希望它们是不同的模板化类型。 objective 是我想更新这些对象中的每一个并将它们保存的变量值存储为字符串。例如:
template <typename T> struct VariableToString
{
VariableToString(T& varArg) : variable(varArg){};
T& variable;
std::string variableAsString;
void update()
{
variableAsString = std::to_string(variable); // <--- Compiler knows which overloaded function to call, but not through a pointer to this struct at runtime
}
}
然后我想要 std::vector 这些对象,这样我就可以遍历所有对象并将变量值转换为字符串。我不确定 how/if 我能做到这一点。基本上是这样的:
std::vector<Idontknow*> myVector;
for (auto i : myVector) i->update();
通常你会有一个指向基 class 的指针向量,让虚拟化处理要调用的函数。但是在这种情况下我想知道是否可以根据模板的类型来处理。我想到了 RTTI,它是否能够识别 "variable" 是什么类型并调用适当的 to_string() 函数?
我是否必须为每个版本创建一个新的派生版本?喜欢:
struct BaseClass
{
virtual void update() = 0;
}
struct DoubleToString : BaseClass
{
double& variable
void update() override;
}
std::vector<BaseClass*> myVector;
for (auto i : myVector) i->update();
让你派生class模板化:
struct BaseClass
{
virtual void update() = 0;
}
template <typename T> struct VariableToString : BaseClass{/*...*/}
然后你就可以随心所欲地使用它了:
std::vector<BaseClass*> myVector;
/*...*/
for (auto i : myVector) i->update();
尽管考虑改用智能指针,例如
std::vector<std::unique_ptr<BaseClass>> myVector;
/*...*/
for (auto i : myVector) i->update();
或使用 shared_ptr<>
代替 unique_ptr
。
如果您只有一个模板 class 就很容易完成这项工作。但是,如果您的模板是任何其他 class 的包装器,您也可以使用它,只要它派生自公共基础 class 即可调用正确的虚拟方法。这与RTTI无关!
使用包装器可以使用没有公共基础 class 的 classes。您还可以为 classes 专门化您的包装器,它们具有语义相同但名称和签名不同的函数。
class Base
{
public:
virtual std::string ToString() = 0;
virtual ~Base() {}
};
class A
{
public:
std::string GetString() { return "From Type A"; }
};
class B
{
public:
std::string GetString() { return "From Type B"; }
};
class C
{
public:
void Name(std::string& name)
{
name="From Type C";
}
};
template < typename Inner >
class Wrapper: public Base, Inner
{
public:
std::string ToString() override { return Inner::GetString(); }
};
template <>
class Wrapper<C>: public Base, C
{
public:
std::string ToString() override
{
std::string name;
C::Name(name);
return name;
}
};
int main()
{
std::vector< Base*> elements;
elements.push_back( new Wrapper<A>);
elements.push_back( new Wrapper<B>);
elements.push_back( new Wrapper<C>);
for ( auto& el: elements )
{
std::cout << el->ToString() << std::endl;
}
for ( auto& el: elements )
{
delete el;
}
}