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.
Czy próbowałeś to z nowszej wersji dzyń (jak 3.8) i nowszy gcc (jak 5.3)? Może być pouczające ... –
Przeważnie zminimalizowane repro: http://coliru.stacked-crooked.com/a/713fbbbca7e8b8c5. Winię buforowanie. –
Zgłoszono jako https://gc.gnu.org/bugzilla/show_bug.cgi?id=70642 –