6

Microsoft 编译器 (Visual Studio 2017 15.2) 拒绝以下代码:

#include <type_traits>

struct B
{ 
    template<int n, std::enable_if_t<n == 0, int> = 0>
    void f() { }
};

struct D : B
{
    using B::f; 
    template<int n, std::enable_if_t<n == 1, int> = 0>
    void f() { }
};

int main()
{
    D d;
    d.f<0>();
    d.f<1>();
}

错误是:

error C2672: 'D::f': no matching overloaded function found
error C2783: 'void D::f(void)': could not deduce template argument for '__formal'
note: see declaration of 'D::f'

Clang 也拒绝它:

error: no matching member function for call to 'f'
    d.f<0>();
    ~~^~~~
 note: candidate template ignored: disabled by 'enable_if' [with n = 0]
    using enable_if_t = typename enable_if<_Cond, _Tp>::type;

GCC 完全接受它。哪个编译器是对的?

添加:

使用 SFINAE 的形式

template<int n, typename = std::enable_if_t<n == 0>>
...
template<int n, typename = std::enable_if_t<n == 1>>

GCC 也会产生错误:

error: no matching function for call to ‘D::f<0>()’
 d.f<0>();
        ^
note: candidate: template<int n, class> void D::f()
 void f()
      ^
note:   template argument deduction/substitution failed:
4

1 回答 1

5

将 cppleaner 的评论变成答案:

namespace.udecl#15.sentence-1

当 using-declarator 将基类中的声明带入派生类时,派生类中的成员函数和成员函数模板会覆盖和/或隐藏同名的成员函数和成员函数模板,parameter-type-list,cv-基类中的限定和引用限定符(如果有)(而不是冲突)

不幸的是,模板参数不计算在内,并且两者f都有空的参数类型列表,不是 const 也没有引用限定符。

Derived::f所以隐藏起来Base::f

gcc 接受该代码是错误的。

所以修复它的方法是默认参数(返回的类型也不计算在内):

struct B
{ 
    template <int n>
    void f(std::enable_if_t<n == 0>* = nullptr) { }
};

struct D : B
{
    using B::f; 
    template <int n>
    void f(std::enable_if_t<n == 1>* = nullptr) { }
};
于 2017-08-09T11:41:19.093 回答