I'm trying to combine the approaches used in this answer for detecting whether a class has a member variable x
with this answer to select different implementations depending on that using enable_if
.
Basically, I want to write a trait class that, given a type T
, provides access to the member T::x
if it exists, and provides a default value otherwise.
The following code does not compile on g++: (Compiler Explorer)
#include <iostream>
#include <type_traits>
// classes with / without x member
struct WithX { static constexpr int x = 42; };
struct WithoutX {};
// trait to detect x
template <typename T, typename = void>
struct HasX : std::false_type { };
template <typename T>
struct HasX <T, decltype((void) T::x)> : std::true_type { };
// trait to provide default for x
template <typename T>
struct FooTraits
{
template <bool enable = HasX<T>::value>
static constexpr std::enable_if_t< enable, size_t> x() { return T::x; }
template <bool enable = HasX<T>::value>
static constexpr std::enable_if_t<!enable, size_t> x() { return 1; }
};
int main() {
std::cout << HasX<WithX>::value << std::endl;
// Uncomment the following line to make this compile with g++
//std::cout << HasX<WithoutX>::value << std::endl;
std::cout << FooTraits<WithoutX>::x() << std::endl;
}
g++ gives error messages that
error: 'x' is not a member of 'WithoutX'
struct HasX <T, decltype((void) T::x)> : std::true_type { };
in the part which should detect whether x
is a member in the first place. Curiously though, if I uncomment the second to last line which instantiates HasX<WithoutX>::value
by itself, g++ compiles without errors (Compiler Explorer).
Both clang and msvc compile without a problem on Compiler Explorer.
What's wrong here?