I have a templated class for which I would like to provide a constexpr integer whose value is determined by the presence or absence of a constexpr integer in the template parameter:
template<typename Traits>
class Foo
{
static constexpr int MaxDegree =
std::conditional<
std::is_integral<Traits::MaxDegree>::value,
std::integral_constant<int, Traits::MaxDegree>,
std::integral_constant<int, 0>
>::value;
};
struct TraitA { };
struct TraitB { constexpr static int MaxDegree = 1; };
int main()
{
std::cout
<< Foo<TraitA>::MaxDegree /* should be 0 */ << " "
<< Foo<TraitB>::MaxDegree; /* should be TraitB::MaxDegree == 1 */
<< "\n";
}
Obviously, this doesn't work since std::is_integral
fails for TraitA. Is there anything that will work?
I'm constrained to c 11.
CodePudding user response:
Traits::MaxDegree
yields a compiler error, if the member doesn't exist. This means you cannot use this code as part of the expression directly.
You could use constexpr functions with SFINAE to implement this though:
template<class T>
constexpr typename std::enable_if<std::is_integral<decltype(T::MaxDegree)>::value, int>::type GetMaxDegree()
{
return T::MaxDegree;
}
template<class T>
constexpr int GetMaxDegree(...) // this one is only used, if the first version results in a substitution failure
{
return 0;
}
template<typename Traits>
class Foo
{
public:
static constexpr int MaxDegree = GetMaxDegree<Traits>();
};
CodePudding user response:
The std::conditional
provides the condtional member type
, according to the passed std::is_integral<Traits::MaxDegree>::value
not a value
. Hence, you have the error.
Is there anything that will work?
You can use goodold SFINAE here, as follows:
#include <type_traits>
template <typename T>
constexpr auto Foo() -> typename std::enable_if<std::is_integral<decltype(T::MaxDegree)>::value, std::integral_constant<int, T::MaxDegree>>::type
{
return std::integral_constant<int, T::MaxDegree>();
}
template <typename T>
constexpr auto Foo() -> typename std::enable_if<!std::is_integral<decltype(T::MaxDegree)>::value, std::integral_constant<int, 0>>::type
{
return std::integral_constant<int, 0>();
}
Now you can
struct TraitA { constexpr static float MaxDegree{}; };
struct TraitB { constexpr static int MaxDegree = 1; };
int main()
{
std::cout
<< Foo<TraitA>() << " " // prints 0
<< Foo<TraitB>(); // prints 1
}