【问题标题】:'Cannot be overloaded' error while trying to enable SFINAE with enable_if尝试使用 enable_if 启用 SFINAE 时出现“无法重载”错误
【发布时间】:2020-01-17 18:09:57
【问题描述】:

我只是在 C++ 中使用 std::enable_if 尝试使用 SFINAE。我以为我理解了理论部分,直到我无法编译以下代码。更令人困惑的是 Visual Studio 和 Linux 上的不同行为。只要您不取消注释(Calculator<int> cInt;),此粘贴的代码就会在 VS 上编译。但是,使用 GCC 它会给我编译错误。我已经在 STL 实现中看到了这种代码,我真的期待更多标准化的实现无处不在。无论如何,您能否在这里检查并提出我的理解存在哪些差距?

template<typename T>
class Calculator
{
public:
    typename enable_if<is_arithmetic<T>::value, T>::type 
    addition(T a, T b)
    {
        return a + b;
    }
    typename enable_if<!is_arithmetic<T>::value, T>::type
    addition(T a, T b)
    {
        cout << "Default\n";
        return a;
    }
};

void SFINAE()
{
//  Calculator<int> cInt; 
}


int main ()
{
    SFINAE();
    return 0;
}

GCC 8.1 的错误日志: j

doodle.cpp:30:3: error: 'typename std::enable_if<(! std::is_arithmetic<_Tp>::value), T>::type Calculator<T>::addition(T, T)' cannot be overloaded with 'typename std::enable_if<std::is_arithmetic<_Tp>::value, T>::type Calculator<T>::addition(T, T)'
   addition(T a, T b)
   ^~~~~~~~
jdoodle.cpp:25:3: note: previous declaration 'typename std::enable_if<std::is_arithmetic<_Tp>::value, T>::type Calculator<T>::addition(T, T)'
   addition(T a, T b)

当您使用 int 取消注释 Calculator 类初始化时,VS 上的错误日志:

sfinae.h(17): error C3646: 'addition': unknown override specifier
sfinae.h(17): error C2059: syntax error: '('
sfinae.h(18): error C2334: unexpected token(s) preceding '{'; skipping apparent function body

【问题讨论】:

    标签: c++ c++11 templates template-meta-programming sfinae


    【解决方案1】:

    在一个类中,SFINAE 适用于模板方法和方法的模板参数。

    所以

    typename enable_if<is_arithmetic<T>::value, T>::type 
    addition(T a, T b)
    {
        return a + b;
    }
    

    无法工作,因为您尝试将 SFINAE 应用于非模板方法和测试 (is_arithmetic&lt;T&gt;::value),该测试 (is_arithmetic&lt;T&gt;::value) 位于类的模板参数上。

    你应该尝试一下

    template <typename U = T>
    typename enable_if<is_arithmetic<U>::value, T>::type 
    addition(T a, T b)
    {
        return a + b;
    }
    

    这样,模板就变成了带有模板参数 (U) 的模板 默认类型 (T) 并且您对方法的模板参数进行了 SFINAE 测试。

    其他 addition() 方法也一样。

    为了避免有人“劫持”你的代码解释错误的模板参数

    Calculator<std::string>  cs;
    
    cs.add("a", "b");  // call the Default version
    cs.template add<int>("a", "b"); // call the arithmetic version!!!
    

    你可以强加UT是同一类型

    template <typename U = T>
    typename std::enable_if<std::is_arithmetic<U>::value
                         && std::is_same<T, U>::value, T>::type 
    addition(T a, T b) //   ^^^^^^^^^^^^^^^^^^^^^^^^^
    {
        return a + b;
    }
    

    【讨论】:

    • 为了避免有人覆盖模板参数推导,您还可以执行template &lt;int&amp;... ExplicitArgumentBarrier, typename U = T&gt; 之类的操作(abseil 就是这样做的)。
    猜你喜欢
    • 1970-01-01
    • 2015-10-17
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-29
    相关资源
    最近更新 更多