【问题标题】:Can an element in a heterogenous array know what templated type it is?异构数组中的元素能否知道它是什么模板类型?
【发布时间】:2017-04-21 12:44:17
【问题描述】:

我想在一个数组中创建一大堆对象,并且我希望它们是不同的模板类型。目标是我想更新这些对象中的每一个并将它们保存的变量值存储为字符串。例如:

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,这样我就可以遍历所有对象并将变量值转换为字符串。我不确定如何/是否可以做到这一点。基本上是这样的:

std::vector<Idontknow*> myVector;
for (auto i : myVector) i->update();

通常你会有一个指向基类的指针向量,并让虚拟化处理要调用的函数。但在这种情况下,我想知道是否可以根据模板的类型进行处理。我想到了RTTI,那能不能识别出“变量”是什么类型并调用相应的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();

【问题讨论】:

  • 没有。没有“模板类型”或“模板类型”之类的东西。
  • 如果您的类型依赖于基类,那么模板没有什么特别之处。模板的实例只是一种类型。该类型的对象必须不知道它所构建的模板类型。对于您的设计,它看起来只是从一个通用的基类派生而来,然后简单地完成这项工作。

标签: c++ class templates virtual rtti


【解决方案1】:

让你的派生类模板化:

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&lt;&gt; 代替unique_ptr

【讨论】:

  • 当然,我错过了它,它是如此明显。谢谢。
【解决方案2】:

如果您只有一个模板类,那么完成这项工作很容易。但是,如果您的模板是任何其他类的包装器,则只要它是从公共基类派生的,您就可以使用它来调用正确的虚拟方法。这与RTTI无关!

使用包装器可以使用没有公共基类的类。您还可以专门针对类的包装器,这些类具有具有相同语义但名称和签名不同的函数。

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; 
    }

} 

【讨论】:

    猜你喜欢
    • 2017-04-01
    • 1970-01-01
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-29
    相关资源
    最近更新 更多