2017-08-08 107 views
5

微軟編譯器(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' 

鏘也拒絕它:

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: 
+0

無關:您可能需要使用一個虛函數SFINAE基類和派生方法來區分,而不是。 –

+0

@HenriMenke我不知道原始用例是什麼,你也不知道,但是虛函數實現了與這裏顯示的完全不同的東西。這是利用實現繼承,而不是多態,並且它使得這兩個函數對於D的用戶可用。虛擬是關於多態的,並且它只有一個可用於D的用戶的功能。 –

+0

@ Jarod42固定標籤,謝謝。 – Evgeny

回答

2

談到cppleaner的評論到一個答案:

namespace.udecl#15.sentence-1

When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting)

不幸的是,模板參數不計及兩個f具有空參數類型列表,不是const的,沒有REF-預選賽。

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