I want to have a type trait for T that returns the value of a static member 'X' if it exists in T, otherwise a default value.
It can be done this way
// we define our type trait here
template<typename T> struct get_X { static constexpr int value = -1; };
// and a specialization for types holding the required member
template<typename T> static constexpr bool has_X = requires { T::X; };
template<typename T> requires(has_X<T>) struct get_X<T> { static constexpr int value = T::X; };
struct foo { static constexpr int X = 3; };
struct bar { static constexpr int Y = 5; };
static_assert (get_X<foo>::value == 3);
static_assert (get_X<bar>::value == -1);
int main() {}
This code works but is pretty cumbersome.
Moreover, if I want to have different type traits for other members like 'get_Y', it could lead to a lot of code.
Question: is there a simpler way to define such a type trait ?
Using if constexpr
, you don't need partial specialisations:
template<typename T>
inline constexpr decltype(auto) get_X_v = []() -> decltype(auto) {
if constexpr (requires { T::x; }) {
return T::x;
} else {
return -1;
}
}();
You might be able to inline this into wherever you use it and get rid of the trait entirely.