2012-12-31 11 views
6

Ten kod nie skompilować w większości kompilatorów, ale najpierw ja intuicyjnie spodziewać SFINAE mnie chronić:SFINAE, odliczenie vs. instancji

typedef void (*A)(); 

template < typename T > 
struct a_metafun { typedef typename T::type type; }; 

template < typename T > 
typename a_metafun<T>::type f(T) {} 

template < typename T> 
void f(T(*)()) {} 

int main() { f(A()); } 

mogę rozwiązać ten problem w co najmniej dwa sposoby:

1) Zmiana definicji "metafun" (f) w celu:

template < typename T > typename T::type f(T) {}

2) określenie "a_metafun" tak, że analizuje T i ma typ jeśli T i ma jeden i nie f to nie ... ale instancję bez błędów w obu kierunkach:

BOOST_MPL_HAS_XXX_TRAIT_DEF(type) 

typedef < template T, bool = has_type<T>::value > 
struct a_metafun { }; 

typedef < template T > 
struct a_metafun<T, true> { typedef typename T::type type }; 

Po patrząc na 14.8.2 (C++ 03) wygląda mi na to, że dokładnie określa, na jakich można zastosować warunki SFINAE. Czy jest lepsze miejsce do patrzenia? Niepowodzenie w tworzeniu już wydedukowanego szablonu, nawet podczas odliczania innego, nie wydaje się być zawarte w tym wykazie.

Innym kierunkiem, który podjąłem, aby interpretować, co sprawia, że ​​jest to niezgodne z prawem, jest to, że odliczenie a_metafun już się odbyło i powstanie jego wnętrzności jest przyczyną błędu. SFINAE nie ma zastosowania podczas tworzenia instancji, ale tylko podczas dedukcji, czy też się mylę? Jednak w drugim przypadku, a_metafun jest poprawne i poprawnie utworzone, ale po prostu nie ma wewnątrz definicji "typu", co oznacza, że ​​szablon próbujący utworzyć wystąpienie zawodzi z powodu zamiany.

Zasadniczo zastanawiam się, co w standardzie określa zachowanie, którego jestem świadkiem. Każdy kompilowany przeze mnie uskarżałam się, nawet na comeau. Uważam, że mają rację, nie jestem do końca pewien, dlaczego.

A więc, eksperci ... co jest? Dlaczego instancja typu, nawet w kontekście dedukcji w f(), powoduje błąd, a nie wykluczenie SFINAE?

+0

myślę, że nie powinno się w C++ 11, a nie w C++ 03 chociaż. Zasada SFINAE (a raczej * słowa *) została nieznacznie zmieniona w C++ 11. – Nawaz

Odpowiedz

2

SFINAE nie będzie Cię tam chronił, wystąpi błąd po odjęciu typu. Jednak powinno to działać:

template < typename T, typename Type = typename T::type > 
struct a_metafun { typedef Type type; }; 

Przez accesing T::type w parametrem domyślnym szablonie możemy spowodować to się stało w momencie podstawienia, a w tym czasie SFINAE kopnięć w

EDIT:. Po przemyśleniu jeszcze więcej, nie jestem do końca pewien, dlaczego twoja obecna implementacja zawodzi. Myślę, że to dlatego, że a_metafunma element członkowski typu type, który powoduje błąd kompilacji; Byłoby inaczej, gdyby a_metafun w ogóle nie miał elementu typu type.

+0

Zobacz moją odpowiedź, dlaczego nie powiedzie się w C++ 11. – Nawaz

4

W specyfikacji C++ 03, zasada SFINAE jest nieco niejasna, pozwalając autorom kompilacji przejść do dowolnej długości, aby znaleźć błąd substytucji w SFINAE. Odpowiedni tekst §14.8.2/2 z C++ 03 mówi,

- [...] Jeśli się na zmianę w parametrze szablonu lub w rodzaju funkcji wyników szablon funkcji w nieprawidłowym typu, nieudane odliczanie typu [...]

Dalej wyjaśnia kilka przyczyn niepowodzenia, ale żaden z nich nie mówi, w którym momencie niepowodzenie zastąpienia należy uznać za SFINAE. Więc myślę, że twój kod może działać poprawnie w C++ 03 (lub może nie, w zależności od tego, jak autorzy interpretują tekst, co i tak jest mylące).

Ale poprawiono sformułowania w C++ 11 usuwając niejasność. Jest napisane w §14.8.2/8,

Jeśli wynikiem zastąpienia jest niepoprawny typ lub wyrażenie, odliczenie nie powiedzie się. Nieprawidłowy typ lub wyrażenie to taki, który byłby źle sformułowany, gdyby został zapisany przy użyciu podstawionych argumentów. [Uwaga: Sprawdzanie dostępu odbywa się w ramach procesu zastępowania. -end note] Tylko niepoprawne typy i wyrażenia w danym typie funkcji i typach parametrów szablonu mogą spowodować błąd dedukcji.

Termin „bezpośredni kontekst” jest ciekawy, i myślę, że odnosi się do danej sytuacji. Bardziej konkretnie, niepowodzenie substytucji w meta-funkcji a_metafun nie jest uważane za "bezpośredni kontekst" typu funkcji. Jest źle sformułowany w C++ 11, a nie SFINAE.

Definicja "bezpośredniego kontekstu" nie jest wystarczająco jasna w C++ 11. Oto jeden aktywny problem:

+1

Interesujące naprawdę! Nie wiedziałem o tej zmianie w _SFINAE_. Dziękuję Ci –