根据类型返回一个值

Return a value depending of type

本文关键字:一个 类型 返回      更新时间:2023-10-16

考虑以下示例

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(固定)

其次,当Typevoid:时,您可以专门化该函数以采取不同的操作

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确保所有工作都由编译器完成,而使用typeiddynamic_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;
}; 
相关文章: