Mix decltype and enable_if

It seems that using decltype with SFINAE enable_if not easy. I tried to write go using enable_if three different ways. They all failed with a compiler error (with GCC literally: "error:" thing "is not a member of" foo "and the creation context).

 #include <type_traits> struct foo { enum { has_thing = false }; }; struct bar { enum { has_thing = true }; static int thing() { return 0; } }; template <typename T> struct Test { /*auto go(typename std::enable_if<T::has_thing, int>::type=0) -> decltype(T::thing()) { return T::thing(); }*/ /*typename std::enable_if<T::has_thing, decltype(T::thing())>::type go() { return T::thing(); }*/ template <bool B=T::has_thing, typename std::enable_if<B, int>::type = 0> auto go() -> decltype(T::thing()) { return T::thing(); } }; int main() { Test<bar> b; Test<foo> f; } 

I can see what the problem is - decltype should happen before enable_if even gets a chance to exclude this function. The question remains, how to work and get this behavior? A simple, general way to do this without resorting to writing the has_thing for use in enable_if ?

Tested with both g ++ 4.7 and clang ++ 3.0.

+6
source share
2 answers

SFINAE will work if the go method is a template method:

 template <typename T> struct Test { template <class U = T> auto go() -> decltype(U::thing()) { return T::thing(); } }; 

You can also use the has_thing value, but you don’t have to do this, since SFINAE will take care of this in the above example:

 template <class U = T, typename std::enable_if<U::has_thing, int>::type = 0> auto go() -> decltype(U::thing()) { return T::thing(); } 

Then:

 int main() { Test<bar> b; Test<foo> f; b.go(); // Works! f.go(); // Fails! } 
+5
source

Of course your SFINAE is not working. The go function is not a template, so SFINAE cannot be used. Also, it should work fine with decltype (you really don't need the has_thing flag).

Eg. this works great (and plays great with other overloads):

 template <class U> auto go(Test<U> t) -> decltype(U::thing()) { return U::thing(); } 
0
source

Source: https://habr.com/ru/post/919499/


All Articles