2017-08-08 4 views
5

compilateur Microsoft (Visual Studio 2017 15.2) rejette le code suivant:résolution de surcharge entre les membres du modèle dans la base et les classes dérivées

#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>(); 
} 

L'erreur est:

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 rejette aussi:

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 l'accepte parfaitement. Quel compilateur a raison?

Addition:

Avec SFINAE sous la forme

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

GCC produit également une erreur:

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

Aucun lien: Vous voulez probablement utiliser une fonction virtuelle pour différencier entre la base et la méthode dérivée plutôt que SFINAE . –

+0

@HenriMenke Je ne sais pas quel était le cas d'utilisation original, et vous non plus, mais les fonctions virtuelles réalisent quelque chose de complètement différent de ce qui est montré ici. Ceci tire parti de l'héritage de l'implémentation, pas du polymorphisme, et rend les deux fonctions accessibles aux utilisateurs de D. virtual à propos du polymorphisme, et n'aurait qu'une seule fonction disponible pour les utilisateurs de D. –

+0

@ Jarod42 Balise fixe, merci. – Evgeny

Répondre

2

Tourner le commentaire de cppleaner dans une réponse:

De 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)

Malheureusement, le paramètre de modèle ne compte pas et les deux f a paramètre de type liste vide, ne sont pas const et non-qualification réf.

Derived::f donc cache Base::f.

gcc a tort d'accepter ce code.

Ainsi, la manière de le corriger est par argument par défaut (type retourné ne compte pas non plus):

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