Home > database >  Declare a constexpr static member that is a function of a potentially-absent member in a template pa
Declare a constexpr static member that is a function of a potentially-absent member in a template pa

Time:05-06

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 
   
}

(See a demo)

  • Related