C++中确定变量模板类型的正确方法

Correct way of determening the template type of variable in C++

考虑以下几点:

class fooBase{
public:
       enum dataType {fooInt, fooFloat, fooInvalid};
       fooBase(){}

       /* void getLocation .. setLocation .. */

       virtual dataType getDataType() = 0;

private:
       int fooDataLocation;
};

template <typename T> class fooDataPoint : public fooBase{
public:
       fooDataPoint(T foodat) :
       fooData(foodat){}

       dataType getDataType(){
                if(typeid(float) == typeid(T))
                return fooFloat;
                if(typeid(int) == typeid(T))
                return fooInt
                return fooInvalid;
       }


private:
        T fooData;
};

template <typename T> class calculatableFooDataPoint : public fooBase{
public:
       fooDataPoint(T foodat, T bardat) :
       fooData(foodat){}

       dataType getDataType(){
                if(typeid(float) == typeid(T))
                return fooFloat;
                if(typeid(int) == typeid(T))
                return fooInt
                return fooInvalid;
       }

       void doCalculation(){
                foodata *= barData;
       }

       /* .. getData .. */
private:
        T fooData;
        T barData;
};

std::vector<foobase *> fooVector;

这将使我能够在向量中存储不同类型的数据。然后,当我需要转换时,我可以先检查数据类型,然后转换为正确的 class 类型,而不是遍历无穷无尽的 dynamic_case<class<type> *>(pointer) 列表。

同样在序列化和反序列化数据点时(我只需要保存结构,而不是已处理的实际数据),我可以只使用 getDataType 来确定类型并编写它的序列化形式。

我想我的底线是,使用 typeid(type) 进行比较是个坏主意,为什么?

其次,是否有设计模型可以涵盖这样的案例?

I guess my bottom line is, is using typeid(type) for comparision a bad idea, and why?

在这种情况下,我相信是的。 T 的类型在编译时已知,因此没有理由通过一系列 if 来确定您已经知道的内容。您可以为此编写一个简单的元函数。另外,不需要使用动态调度来确定函数的类型,您可以将值存储在基类中:

class fooBase {
    enum dataType { fooInt, fooFloat, … };
    const dataType type;
    fooBase(dataType t) : type(t) {}
    …
    dataType getDataType() const { return type; }
};

template <typename T>
struct DataType;
template <> struct DataType<int>   
   { static const dataType value = fooBase::fooInt; };
template <> struct DataType<float> 
   { static const dataType value = fooBase::fooFloat; };

那么 dataPoint 的构造函数将是:

template <typename T>
fooDataPoint<T>::fooDataPoint(T data) 
: fooBase(DataType<T>::value) 
, fooData(data)
{}

除此之外,该设计在可扩展性方面并不是那么好,因为需要为任何您可能想要包含的类型 T 更新基础(扩展枚举),但是如果set 是预先知道的,这可能不是太大的负担。

如果选项数量有限,对象的大小相差不大,您可以使用像boost::variant这样的预建解决方案,它具有优点是它不需要动态分配并且不强制层次结构。潜在的缺点是,作为一个有区别的联合,每个对象的大小大约是它所拥有的最大类型的大小(sizeof)。