I'm reading the C++ Programming Language, 4th Edition by Bjarne Stroustrup and in Chapter 28 about metaprogramming in Section 28.4.4 there is a code similar to the following example:
#include <type_traits>
#include <string>
struct substitution_failure {};
template <typename T>
struct substitution_succeeded : std::true_type {};
template <>
struct substitution_succeeded<substitution_failure> : std::false_type {};
double f(double x)
{
return x;
}
template <typename T>
class get_f_result
{
template <typename X>
static auto check(const X& x) -> decltype(f(x));
static substitution_failure check(...);
public:
using type = decltype(check(std::declval<T>()));
};
template <typename T>
struct has_f : substitution_succeeded<typename get_f_result<T>::type> {};
template <typename T>
constexpr bool has_f_v()
{
return has_f<T>::value;
}
template <typename T>
struct Foo
{
template <typename = std::enable_if_t<has_f_v<T>()>>
T foo(const T& t)
{
return f(t);
}
};
int main()
{
Foo<std::string> foo;
return 0;
}
I expect thanks to the SFINAE the example to compile successfully after the foo
method of the Foo
class is never called, but it compiles only on MSVC and refuses to compile on GCC and Clang with the following error:
error: no type named 'type' in 'struct std::enable_if<false, std::__cxx11::basic_string<char> >'
2611 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
Why the example compiles only on MSVC and how to fix it to compile successfully also on GCC and Clang?