2016-04-12 12 views
6

Kilka pytań dla ekspertów C++ 11.g ++ i clang ++ inne zachowanie z błędem SFINAE i SFINAE

Walczę z SFINAE i natknąłem się na dziwny przypadek, w którym g ++ (4.9.2) i clang ++ (3.5.0) zachowują się inaczej.

Przygotowałem następujący przykładowy kod. Przykro mi, ale nie potrafię zrobić tego w sposób bardziej zwięzły.

#include <string> 
#include <iostream> 
#include <typeinfo> 
#include <type_traits> 

template <typename X> 
class foo 
{ 
    private: 
     template <typename R> 
     using enableIfIsInt 
     = typename std::enable_if<std::is_same<X, int>::value, R>::type; 

    public: 
     foo() 
     { } 

     template <typename R = void> 
     enableIfIsInt<R> bar() 
      { std::cout << "bar: is int\n"; } 

     void bar() 
     { 
     std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{" 
      << typeid(enableIfIsInt<void>).name() << "}\n"; 
     } 
}; 


int main() 
{ 
    foo<long> fl; 
    foo<int> fi; 

    fl.bar(); 
    fi.bar(); 

    return 0; 
} 

Moim pomysłem było stworzenie szablonu foo<X> klasę, która (poprzez SFINAE) może określić sposób, w jednym lub w inny sposób, w zależności od argumentu X szablonu.

Program skompilować również z g ++ 4.9.2 ale brzękiem ++ 3.5.0 daje następujący błąd

test.cpp:13:36: error: no type named 'type' in 
     'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable 
     this declaration 
     = typename std::enable_if<std::is_same<X, int>::value, R>::type; 
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~ 
test.cpp:26:23: note: in instantiation of template type 
     alias 'enableIfIsInt' requested here 
      << typeid(enableIfIsInt<void>).name() << "}\n"; 
        ^
test.cpp:36:7: note: in instantiation of member function 
     'foo<long>::bar' requested here 
    fl.bar(); 
    ^
1 error generated. 

Przypuszczam, że ma rację dzyń ++ ale moje pierwsze pytanie do C++ 11 ekspertów: kto nie? g ++ lub clang ++?

O g ++ produkowanego wyjścia programu, to następujące

bar: isn't int; is [i]{v} 

tak g ++ wydaje się ignorować dyspozycję fl.bar();.

Teraz trochę zmiana: i modyfikować drugą wersję foo<X>::bar() w ten sposób

void bar() 
    { std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; } 

usuwanego z std::enable_if wewnątrz ohydę funkcyjnego. Teraz zarówno g ++ i brzęk ++ są kompilowanie bez problemów i wyjścia, zarówno dla skompilowanych wersji programu, jest

bar: isn't int; is [l] 
bar: isn't int; is [i] 

Więc moje drugie pytanie brzmi: co robię źle? Dlaczego w przypadku int nie mogę uzyskać wersji "is int" z foo<X>::bar()?

Bądź cierpliwy, jeśli robię coś głupiego: Próbuję się nauczyć C++ 11.

Przepraszam za mój zły angielski.

+1

Czy próbowałeś to z nowszej wersji dzyń (jak 3.8) i nowszy gcc (jak 5.3)? Może być pouczające ... –

+0

Przeważnie zminimalizowane repro: http://coliru.stacked-crooked.com/a/713fbbbca7e8b8c5. Winię buforowanie. –

+2

Zgłoszono jako https://gc.gnu.org/bugzilla/show_bug.cgi?id=70642 –

Odpowiedz

6

Błąd klang nie pochodzi od błędu zastąpienia. To pochodzące stąd:

void bar() 
    { 
    std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{" 
     << typeid(enableIfIsInt<void>).name() << "}\n"; // <== 
    } 

enableIfIsInt<void> nie znajduje się w bezpośrednim kontekście, że to ciężka niewydolność dla X nie int. Po prostu nie możesz użyć tego wyrażenia w tym kontekście.

Po usunięciu - szablon bez nazwy bar() jest zawsze wywoływany. Dzieje się tak dlatego, że obie funkcje są równoważnymi dopasowaniami, a szablony inne niż szablony są preferowane w stosunku do szablonów w rozdzielczości przeciążania.

Tak więc prawdziwym rozwiązaniem jest użycie znacznika dyspozytorskich:

void bar() { bar(std::is_same<X, int>{}); } 

void bar(std::true_type) { 
    std::cout << "bar: is int\n"; 
} 

void bar(std::false_type) { 
    std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; 
} 

z których oba kompilatory szczęśliwie wydajność:

bar: isn't int; is [l] 
bar: is int 
+0

nie skupiałem się na tym, że do szablonów w rozdzielczości przeciążeniowej preferowane są szablony inne niż szablony; dzięki. – max66