基类和派生类中模板成员之间的重载分辨率

时间:2017-08-08 19:19:58

标签: c++ c++14 sfinae overload-resolution using-declaration

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:

1 个答案:

答案 0 :(得分:3)

将cppleaner的评论转化为答案:

来自namespace.udecl#15.sentence-1

  

当using-declarator将基类的声明带入派生类时,派生类中的成员函数和成员函数模板覆盖和/或隐藏具有相同名称的成员函数和成员函数模板,parameter-type-list基类中的cv-qualification和ref-qualifier(如果有的话)(而不是冲突的)

不幸的是,模板参数不计算,f都有空参数类型列表,不是const而且没有ref-qualifier。

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