2015-12-08 2 views
13

Während der Auflösung einer Überladung einer Template-Member-Funktion einer Basisklasse beobachtete ich ein unterschiedliches Verhalten zwischen g ++ (5.2.1-23) und clang (3.8.0), mit -std=c++14.C++ Template-Überladung mit enable_if: anderes Verhalten mit g ++ und clang

#include <iostream> 
#include <type_traits> 

struct Base 
{ 
    template <typename T> 
    auto a(T t) -> void { 
    std::cout<< "False\n"; 
    } 
}; 

template <bool Bool> 
struct Derived : public Base 
{ 

    using Base::a; 
    template <typename T, bool B = Bool> 
    auto a(T t) -> std::enable_if_t<B, void> 
    { 
    std::cout<< "True\n"; 
    } 
}; 

int main() 
{ 
    Derived<true> d; 
    d.a(1); // fails with g++, prints "true" with clang 
    Derived<false> d2; 
    d2.a(1); // fails with clang++, prints "false" with g++ 
} 

Der Aufruf von Derived<true>::a nicht mit g ++ mit der folgenden Meldung:

test.cc: In function ‘int main()’: 
test.cc:28:8: error: call of overloaded ‘a(int)’ is ambiguous 
    d.a(1); 
     ^
test.cc:18:8: note: candidate: std::enable_if_t<B, void> Derived<Bool>::a(T) [with T = int; bool B = true; bool Bool = true; std::enable_if_t<B, void> = void] 
    auto a(T t) -> std::enable_if_t<B, void> 
     ^
test.cc:7:8: note: candidate: void Base::a(T) [with T = int] 
    auto a(T t) -> void { 
     ^

und der Aufruf von Derived<false>::a nicht mit Klirren ++ mit der folgenden Meldung:

test.cc:32:6: error: no matching member function for call to 'a' 
    d2.a(1); 
    ~~~^ 
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with T = int, B = false] 
    using enable_if_t = typename enable_if<_Cond, _Tp>::type; 
             ^

Meine Vermutung ist, dass Sie interpretieren das using Base::a; anders und es wird nicht in clang berücksichtigt, während es in g ++ (vielleicht zu viel) berücksichtigt wird. Was ich dachte, würde passieren, wenn Derivedtrue als Parameter hat, dann wird der Anruf von a() zu Derived Implementierung gesendet, während, wenn der Parameter false ist, der Anruf an Base::a gesendet wird.

Sind beide falsch? Wer hat Recht? An wen sollte ich einen Fehlerbericht senden? Kann jemand erklären, was vor sich geht?

Dank

Antwort

3

Von 3.3.10/p3 Namen versteckt [basic.scope.hiding]:

In einer Funktionsdefinition Mitglied, die Deklaration eines Namens in Block Umfang die Deklaration versteckt ein Mitglied der Klasse mit demselben Namen ; siehe 3.3.7. Die Deklaration eines Members in einer abgeleiteten Klasse (Klausel 10) verbirgt die Deklaration eines Mitglieds einer Basisklasse des gleichen Namens; siehe 10,2

Auch 7.3.3/p15 Die using-Deklaration [namespace.udecl]:

Wenn eine using-Deklaration Namen von einer Basisklasse in einen abgeleiteten Klassenbereich bringt, Funktionen Mitglied und Memberfunktionsvorlagen in der abgeleiteten Klasse , die Memberfunktionen überschreiben und/oder ausblenden und Funktionsschablonen mit demselben Namen, Parametertypliste (8.3.5), cv-qualification und ref-qualifier (falls vorhanden) in einer Basisklasse (eher als widersprüchlich). [Anmerkung: Für die Verwendung von Deklarationen, die einen Konstruktor benennen, siehe 12.9. - Endnote] [Beispiel:

struct B { 
    virtual void f(int); 
    virtual void f(char); 
    void g(int); 
    void h(int); 
}; 
struct D : B { 
    using B::f; 
    void f(int); // OK: D::f(int) overrides B::f(int); 
    using B::g; 
    void g(char); // OK 
    using B::h; 
    void h(int); // OK: D::h(int) hides B::h(int) 
}; 
void k(D* p) 
{ 
    p->f(1); // calls D::f(int) 
    p->f(’a’); // calls B::f(char) 
    p->g(1); // calls B::g(int) 
    p->g(’a’); // calls D::g(char) 
} 

- Ende Beispiel]

Dies wird während Mitgliedsnamen Nachschau aufgelöst. Somit ist es vor der Vorlage Argumentabzug. Folglich, wie in den Kommentaren korrekt TC erwähnt wird, ist die Basisschablonenfunktion ungeachtet des SFINAE-Urteils verborgen.

Daher ist CLANG korrekt und GCC ist falsch.

+2

Es ist entweder versteckt und nicht Teil der Überladung gesetzt, oder es ist sichtbar und so Teil der Überlast eingestellt. "Manchmal versteckt" ergibt keinen Sinn. –

+1

Also, wenn ich richtig verstehe, ist g ++ falsch, weil ein Konflikt mit einem 'using' nicht berücksichtigt werden sollte, und clang ist falsch, denn wenn nichts gefunden wird, sollte es einen Blick auf das' using' werfen, richtig? Daher sollte ich einen Fehlerbericht für beide Compiler einreichen. –

+0

@ VTolmer Basierend auf der Standard-Formulierung glaube ich, dass dies der Fall ist. – 101010