考虑以下示例
template<class Type = void> class MyClass
{
public:
double getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return (/* SOMETHING */) ? (_x) : (_y);
}
protected:
double _x;
static const double _y;
};
/* SOMETHING */
条件可能是什么?
如果模板参数为void,我想返回_x
,否则返回_y
。怎么做?
答案 0 :(得分:12)
首先,你不能返回任何东西,因为函数返回类型是(已修复)void
。
其次,当Type
为void
时,您可以专门化该功能以采取不同的行动:
template<class Type> class MyClass
{
public:
double getValue()
{
return _y;
}
protected:
double _x;
static const double _y;
};
template<>
inline double MyClass<void>::getValue()
{
return _x;
}
答案 1 :(得分:4)
你可以用SFINAE写作:
template<typename Type = void>
class MyClass
{
public:
std::enable_if<std::is_same<Type, void>::value, decltype(_x)> getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return _x;
}
std::enable_if<!(std::is_same<Type, void>::value), decltype(_y)> getValue()
{
return _y;
}
protected:
double _x;
static const double _y;
};
答案 2 :(得分:0)
您可以使用动态强制转换来测试类型。如果转换为不同的类型,动态转换会返回空指针;
这是一个例子。
SomeClass* somePointer = NULL;
somePointer = dynamic_cast<SomeClass*>(someOtherPointer);
if (somePointer)
{
// *someOtherPointer is of type SomeClass
}
else
{
// *someOtherPointer is not of type SomeClass
}
答案 3 :(得分:0)
目前主要问题是您将getValue()
定义为返回void
。
但是我们跳过这个。
需要很好地定义C ++中的函数定义。这意味着它需要具有不可变的返回类型和参数列表以及名称。 (我相信还有几个属性,但这里并不重要。)
您可以重载函数,因此您有一些具有不同参数列表的定义,但是对于具有相同名称的所有函数,返回类型必须相同。如果使用模板,则可以获得不同的返回类型,返回类型将是模板参数。
现在要处理不同类型,我相信有两种方式。一个是使用模板和专业化。
您可以将getValue()
定义为template<T> double getValue();
,然后使用不同的专精来处理原始getValue
的不同分支。在您的示例中,它将是:
//default case
template<typename T> double MyClass<T>::getValue() { return _y; }
//void case
template<> double MyClass<void>::getValue() { return _x; }
第二个选项是使用RTTI机制,该机制允许在运行时确定对象的类型。代码几乎可以像你的一样。 E.g。
double getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return (typeid(Type) == typeid(void)) ? (_x) : (_y);
}
这完全取决于您是否可以在编译期间确定Type。 RTTI方法有其缺点。如果您想要处理更多类型,RTTI允许您通过修改一个函数来执行此操作,而模板方法则需要添加另一个特殊化。我想这取决于一个人喜欢哪条路径...而且模板在设计方面非常好。
编辑:Oopsies ......我错过了你的班级被Type
模仿。所以这实际上应该删除RTTI apporach的问题。如果有人以独家标题来到这里,我会留下答案,因为我认为这仍然是一种有效的方法。
答案 4 :(得分:0)
使用 SFINAE 可确保所有工作都由编译器完成,而使用typeid
,dynamic_cast
等的其他选项则需要一些运行时成本,这些成本完全是不必要的(因为所有信息都在编译时可用)。事实上,这些是最好使用这些方法的非常糟糕的例子。
可能的SFINAE解决方案
template<class Type = void> class MyClass
{
public:
typename std::enable_if< std::is_void<Type>::value, double>::type
getValue() { return _x; }
typename std::enable_if<!std::is_void<Type>::value, double>::type
getValue() { return _y; }
protected:
double _x;
static const double _y;
};