Static statements and SFINAE

Consider this:

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; } 

Besides the clearly missing headers, should this be compiled?

In other words, I ask if a static assertion failure is required when running in a trailing declaration when outputting the return value of a template of an overloaded function in order to stop compilation or if the overload is simply discarded.

In gcc 4.7, compilation fails. I am pretty positive, although this will compile ok in gcc 4.8 (but cannot verify at this very moment). Who is right?

+8
c ++ c ++ 11 sfinae static-assert
source share
2 answers

Compilation should fail in any compatible compiler.

SFINAE rules are based on declarations, not definitions. (Sorry if I use the wrong terminology here.) I mean the following:

For class / structure:

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

For function:

 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 */ } 

In addition, the structure / function property for a given set of template arguments is also subject to SFINAE rules.

Now static_assert can only appear in regions where replacement errors are errors, so if it works, you will get a compiler error.

For example, the following invalid implementation of 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. }; 

Then try this

 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 } 

If you remove the enable_if specialization for false , then the code compiles and outputs

 1 1 
+12
source share

In gcc 4.7, compilation fails. I am pretty positive, although this will compile ok in gcc 4.8 (but cannot verify at this very moment). Who is right?

The condition in your static statement is independent of any template parameter. Therefore, the compiler can immediately evaluate it to false when parsing the template and understand that this statement should work - regardless of whether you really create the template in another place.

The same should be true for any compiler.

+6
source share

All Articles