使用SFINAE启用转换运算符

时间:2014-12-11 21:52:57

标签: c++ templates sfinae typetraits enable-if

我正在尝试使用SFINAE重置operator T()以在T是基本类型时返回副本,并在T是类时使用const引用。

在下面的示例中使用double时,我无法删除第二次重载(std::is_class)。

也就是说,我得到的错误是:

error: no type named ‘type’ in ‘struct std::enable_if<false, const double&>’
operator typename std::enable_if< std::is_class<T>::value, const T&>::type () const
^

我做错了什么?

#include <iostream>
#include <type_traits>

template<typename T>
struct Foo
{
    operator typename std::enable_if<!std::is_class<T>::value, T >::type () const
    {
        return _val;
    }

    operator typename std::enable_if< std::is_class<T>::value, const T&>::type () const
    {
        return _val;
    }

    T _val;
};

int main()
{
    Foo<double> f1;
    f1._val = 0.3;

    double d = f1;
    std::cout << d << std::endl;
    return 0;
}

3 个答案:

答案 0 :(得分:9)

T在您的类成员函数被实例化时已经知道,因此不会发生替换,而不是SFINAE,您会收到一个硬错误。最简单的解决方法是为这些运算符重载引入虚拟模板参数,并将其默认为T,以便仍然可以进行类型推导。

template<typename U = T>
operator typename std::enable_if<!std::is_class<U>::value, U >::type () const
{
    return _val;
}

template<typename U = T>
operator typename std::enable_if< std::is_class<U>::value, const U&>::type () const
{
    return _val;
}

Live demo

答案 1 :(得分:4)

虽然没有解决为什么不丢弃不正确的运算符的问题,但是为了解决手头的特定问题,即通过const ref返回类类型或通过其他人的值,可以使用std::conditional找到解决方案。

template< bool B, class T, class F >
struct conditional;
  

提供成员typedef类型,如果B为真,则定义为T.   编译时间,如果B为假,则为F。

工作示例:

#include <iostream>
#include <type_traits>

template<typename T>
struct Foo
{
    operator typename std::conditional<
        std::is_class<T>::value, const T&, T>::type () const
    {
        return _val;
    }

    T _val;
};

int main()
{
    Foo<double> f1;
    f1._val = 0.3;

    double d = f1;
    std::cout << d << std::endl;
    return 0;
}

答案 2 :(得分:-3)

您应阅读std :: enable_if

的定义

模板&LT; bool B,T级= void&gt; struct enable_if;

“如果B为真,则std :: enable_if具有公共成员typedef类型,等于T;否则,没有成员typedef。”