2013-04-30 16 views
8

Rozważ to:statyczne twierdzenia i SFINAE

template <typename T> 
struct hash 
{ 
    static_assert(false,"Not implemented."); 
}; 

struct unhashable {}; 

template <typename T> 
auto test(const T &t) -> decltype((*(hash<T> const *)nullptr)(t),int); 

void test(...); 

int main() 
{ 
    std::cout << std::is_same<decltype(test(std::declval<unhashable>())),void>::value; 
} 

Oprócz oczywiście brakujących nagłówków, powinno to skompilować?

Innymi słowy, pytam, czy niepowodzenie wyładowania statycznego w kończącym się decltype podczas dedukowania wartości zwracanej przez przeciążony szablon funkcji jest wymagane do zatrzymania kompilacji, lub jeśli przeciążenie należy po prostu odrzucić.

W gcc 4.7 kompilacja nie powiedzie się. Jestem jednak całkiem pozytywny, że skompiluje to ok w gcc 4.8 (ale nie może tego sprawdzić w tej chwili). Kto ma rację?

+0

możliwy duplikat [Jak zmusić klienta do wywoływania wyraźnie wyspecjalizowanego szablonu zamiast podstawowego szablonu?] (http://stackoverflow.com/questions/16286303/how-can-can-i-force--client-to-call- an-explicit-specjalistyczne-szablon-zamiast-t) –

Odpowiedz

12

Kompilacja musi zakończyć się niepowodzeniem w każdym zgodnym kompilatorze.

Reguły SFINAE są oparte na deklaracjach, a nie definicjach. (. Przepraszam, jeśli używam niewłaściwego terminologii tutaj) Chodzi mi o to:

dla klasy/struct:

template < /* substitution failures here are not errors */ > 
struct my_struct { 
    // Substitution failures here are errors. 
}; 

dla funkcji:

template </* substitution failures here are not errors */> 
/* substitution failures here are not errors */ 
my_function(/* substitution failures here are not errors */) { 
    /* substitution failures here are errors */ 
} 

Ponadto , brak istnienia struktury/funkcji dla danego zestawu argumentów szablonu podlega również zasadom SFINAE.

Teraz static_assert może pojawić się tylko w regionach, w których awarie podstawiania są błędami, a zatem jeśli zostanie uruchomiony, otrzymasz błąd kompilatora.

Na przykład następujący byłoby źle realizacja enable_if:

// Primary template (OK) 
template <bool, typename T> 
struct enable_if; 

// Specialization for true (also OK) 
template <typename T> 
struct enable_if<true, T> { 
    using type = T; 
}; 

// Specialization for false (Wrong!) 
template <typename T> 
struct enable_if<false, T> { 
    static_assert(std::is_same<T, T*>::value, "No SFINAE here"); 
    // The condition is always false. 
    // Notice also that the condition depends on T but it doesn't make any difference. 
}; 

Następnie spróbuj tego

template <typename T> 
typename enable_if<std::is_integral<T>::value, int>::type 
test(const T &t); 

void test(...); 

int main() 
{ 
    std::cout << std::is_same<decltype(test(0)), int>::value << std::endl; // OK 
    std::cout << std::is_same<decltype(test(0.0)), void>::value << std::endl; // Error: No SFINAE Here 
} 

Jeśli usuniesz specjalizację enable_if dla false następnie kod kompiluje i wyjścia

1 
1 
+0

Dziękuję za wyczerpujące wyjaśnienie, zaznaczając odpowiedź jako zaakceptowaną. – bluescarni

6

W gcc 4.7 kompilacja nie powiedzie się. Jestem jednak całkiem pozytywny, że skompiluje to ok w gcc 4.8 (ale nie może tego sprawdzić w tej chwili). Kto ma rację?

Warunek w twojej statycznej asercji nie zależy od żadnego parametru szablonu. Dlatego podczas analizowania szablonu kompilator może natychmiast ocenić go na false i uświadomić sobie, że asercja powinna zostać uruchomiona - bez względu na to, czy faktycznie tworzysz szablon nigdzie indziej.

To samo powinno być prawdą w każdym kompilatorze.

+0

Dość jasne, mam zamiar sprawdzić dokładnie, co dzieje się na GCC 4.8 od dłuższego czasu. Domyślam się, że podstawowe pytanie brzmi, czy static_assert() liczy się jako "błąd substytucji" lub coś poważniejszego? – bluescarni

+0

@bluescarni: To nie jest błąd zastąpienia, ale raczej trudny błąd, ponieważ nie występuje w ["bezpośrednim kontekście"] (http://stackoverflow.com/questions/15260685/what-is-exactly-the -immediate-context-in-the-c11-standard-for-whic) typu funkcji i jej typów parametrów szablonu –

+0

@Andy. Wierzę, że fakt, że warunek w 'static_assert' nie zależy od' T' nie robi żadnej różnicy. Proszę spojrzeć na moją odpowiedź i zachęcić ją do poprawy. –