【问题标题】:How do I get the template type of a given element at runtime in C++?如何在 C++ 运行时获取给定元素的模板类型?
【发布时间】:2012-07-06 22:14:04
【问题描述】:

我正在设计一个简单的Array 类,它能够保存任何类型的对象,例如可以在一个对象中保存多种类型数据的向量。 (这是为了学习目的。)

我有一个名为Container 的空基类:

class Container {};

还有一个名为Object的模板化子类:

template <class T>
class Object : public Container {
    T& object;
public:
    Object(T& obj = nullptr) : object(obj) {}
};

我有一个Array 类,它包含一个指向Containers 的指针vector,我用它来保存Objects:

class Array {
    std::vector<Container *> vec;
public:
    template <class T>
    void add_element(const T&);
    auto get_element(int);
};

add_element 将元素存入Objects 并放入vec

template <class T>
void Array::add_element(const T& element)
{
    vec.push_back(new Object<T>(element));
}

get_element 从它的Object 中删除元素并将其传递回调用者。这就是我的问题所在。为了从Object 中删除元素,我需要知道Object 是什么类型:

auto Array::get_element(int i)
{
    return (Object</* ??? */> *)vec[i])->object;
}

有什么方法可以让我找出我存储的对象类型吗?

编辑:既然人们声称这是不可能的,那么这个怎么样。是否有某种方法可以在类中实际存储类型信息? (我知道你可以在 ruby​​ 中做到这一点)。如果可以的话,我可以在每个Object 中存储get_element 的返回类型。

【问题讨论】:

  • @ildjarn:由于 OP 在问题中使用auto,我认为可以安全地假设。
  • @user315052 因为那样使用会更难。 @ildjarn 是的,但如果我decltype(vec[i]) 我只会得到Container *。我需要知道它是什么子类。
  • 去看看boost::any
  • @MichaelDorst 编辑:既然人们声称这是不可能的,那么这个怎么样。是否有某种方法可以在类中实际存储类型信息? (我知道你可以在 ruby​​ 中做到这一点)。如果我能做到这一点,我可以将 get_element 的返回类型存储在每个 Object 中。在 Object 类中,您可以通过 typedef 保存模板参数,例如typedef T object_type;但它不能帮助你。
  • @ForEveR 如何存储类型信息?这只能工作一次(你不能将多个类型定义为同一个标识符,例如typedef T obj_type; ... typedef Q obj_type;),我需要它来处理我添加到Array的每个元素。

标签: c++ templates polymorphism


【解决方案1】:

我正在为您的get_element 考虑此模板的内容。

template <class T>
T& Array::get_element(int i, T &t)
{
    Object<T> *o = dynamic_cast<Object<T> *>(vec[i]);
    if (o == 0) throw std::invalid_argument;
    return t = o->object;
}

Array arr;
double f;
int c;

arr.get_element(0, f);
arr.get_element(1, c);

但是,您也可以使用这个:

template <class T>
T& Array::get_element(int i)
{
    Object<T> *o = dynamic_cast<Object<T> *>(vec[i]);
    if (o == 0) throw std::invalid_argument;
    return o->object;
}

f = arr.get_element<double>(0);
c = arr.get_element<int>(1);

【讨论】:

  • 我不太喜欢你的抛出语句,一般我会抛出一个std::exception,但你的基本想法是好的。没有prb - thx =)
  • @MichaelDorst:编辑完成,问候
  • @MichaelDorst:我看到了你的编辑建议。所以你可以让你的Array 的用户像double f = arr.get_element&lt;double&gt;(i) 这样称呼它吗?因为,我认为arr.get_element(i, f) 更好。
  • 那么我每次调用它时都必须创建一个虚拟变量。这似乎很愚蠢。最好只指定类型。
  • 另外,我稍后会重载operator [],所以我希望调用是vec&lt;double&gt;[i]; 而不是vec[i, f];。我实际上不确定后者是否可行。如果我以这种方式使用它,我将投射到 double 也更清楚。
【解决方案2】:

Array::get_element 这样的函数的返回类型必须在编译时确定。由于Array 类在编译时不知道它存储什么类型的容器,唯一的选择是只返回基Container* 指针。然后该代码的用户可以使用虚函数和/或dynamic_cast 来处理那些通用容器。

【讨论】:

  • 这个类的重点是让我不必每次想要访问一个元素时都使用所有这些语法。 ((Object&lt;Type&gt; *)vec[num].-&gt;object 太乱了。
  • 如果Container 有足够的虚函数,则不需要任何强制转换。
【解决方案3】:

dynamic_cast(),当用于指针时,可用于检查强制类型转换是否实际可行,因为当类型不匹配时它返回 NULL。

但是,您可能需要重新考虑您的设置;如果可以避免动态转换,您不会想要使用它,并且具有级联“如果 object-is-type1 则执行此操作;否则如果 object-is-type2 则执行此操作;否则如果 object-is-type3 ...”几乎总是糟糕设计的肯定标志。

在你的 get_element 中使用 auto 可能是你解决你不知道类型是什么的问题的诀窍——但这不起作用。编译器仍然必须知道返回类型;它不能在运行时改变。

编辑:您也可以退后一步,问自己是否真的需要一个可以存储“任何东西”的数组。我使用 Objective-C 已经很长时间了,它基本上是围绕着这样一个想法构建的,即一切都只是一个“对象”,人们可以在任何东西上调用任何东西,这一切都是在运行时整理出来的。但是,我发现它的实际用途很少见……特别是对于容器,我发现我使用的每个 NSArray 都只有一种类型的对象,或者可能是公共基类的对象,但实际上并不是不同的、不相关的类.

【讨论】:

  • 这种用途很少见,但仍然需要具备这种能力。我最初的想法是创建一个类,我可以将其用作 Obj-C 对象的包装器(以最小化 Obj-C++ 代码,因为它很难维护)。如果我使用向量,我无法处理所有场景,这是有问题的。
猜你喜欢
  • 1970-01-01
  • 2012-01-19
  • 2013-08-04
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 2010-11-02
  • 2017-10-30
  • 2017-11-08
相关资源
最近更新 更多