根据类型返回值

时间:2012-09-26 09:07:44

标签: c++ templates c++11 typetraits

考虑以下示例

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。怎么做?

5 个答案:

答案 0 :(得分:12)

首先,你不能返回任何东西,因为函数返回类型是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;
}

答案 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 可确保所有工作都由编译器完成,而使用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;
};