使用 SFINAE 启用转换运算符

enable conversion operator using SFINAE

本文关键字:运算符 转换 启用 SFINAE 使用      更新时间:2023-10-16

我正在尝试重载operator T()使用 SFINAE 在 T 是基本类型时返回副本,当 T 是类时返回常量引用。

在下面的示例中使用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;
}

> 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;
}

现场演示

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

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

提供成员类型定义类型,如果 B 在 编译时,或者如果 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;
}