根据类型返回一个值
Return a value depending of type
考虑以下示例
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
。如何做到这一点?
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;
}
您可以使用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;
};
您可以使用动态强制转换来测试类型。如果强制转换为其他类型,则动态强制转换将返回null指针;
下面是一个例子。
SomeClass* somePointer = NULL;
somePointer = dynamic_cast<SomeClass*>(someOtherPointer);
if (somePointer)
{
// *someOtherPointer is of type SomeClass
}
else
{
// *someOtherPointer is not of type SomeClass
}
目前的主要问题是您将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机制,该机制允许在运行时确定对象的类型。这个代码可能和你的一模一样。例如
double getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return (typeid(Type) == typeid(void)) ? (_x) : (_y);
}
这完全取决于您是否可以在编译期间确定类型。RTTI方法有其缺点。如果您曾经想要处理更多类型,RTTI允许您通过修改一个函数来实现,而模板方法则需要添加另一个专门化。我想走哪条路取决于一个人的喜好。。。和模板在设计方面相当不错。
编辑:Oopsies。。。我错过了你的课被Type
模板化了。因此,这实际上应该消除RTTI的合理性。不管怎样,如果有人来这里时被唯一的标题所吸引,我会留下答案,因为我相信这仍然是一种有效的方法。
使用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;
};
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- 给定一个类型,如何派生一个泛型更广泛的类型(例如,用于溢出安全求和)?
- 更改可变参数模板中的最后一个类型
- 如何构造一个类型特征,可以判断一个类型的私有方法是否可以在另一个类型的构造函数中调用?
- 有没有办法同时将一个类型分配给C++中的多个模板?
- C++:可以模板化一个类型名称吗
- 有没有一种方法可以使用SFINAE来检测一个类型是否实现了给定的抽象基类
- 给定一个类型为 Container:<T>:Iterator 的函数参数,如何为某些类型的 T 实现特定的重载?
- 期望一个类型,得到一个模板
- 初始化一个类型向量的巨大向量<int>
- 我可以使用预处理器将一个类型声明替换为另一个类型声明吗?
- 具有多种类型的类数组?如何访问数组中的一个类型
- Opencv C++ 声明一个类型为 uint8 的矩阵
- 模板参数列表中只有一个类型名称是什么意思?
- C++模板部分特化:为什么我无法匹配可变参数模板中的最后一个类型
- 为什么我们有一个类型不匹配
- 在函数模板中将一个类型名映射到另一个类型名
- 创建一个类型bool的向量,其中所有值均可初始化为true
- 在C API中定义了一个类型,如何将其与命名空间中的C++类相关联