It seems that using decltype
with SFINAE enable_if
isn't straightforward. I tried writing the go
using enable_if
in three different ways. All of them failed with a compiler error (With GCC literally: "error: 'thing' is not a member of 'foo'" and an instantiation 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
needs to happen before the enable_if
even gets a chance to rule out the function. The question that remains is how to work around and get similar behaviour? Is there a simple, generic way to do this without resorting to writing has_thing
trait to use in the enable_if
?
Tested with both G++ 4.7 and clang++ 3.0.
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 could also use the has_thing
value, but there's no need to do it, since SFINAE will take care of that on 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!
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With