Search code examples
c++c++20c++-concepts

Concept checking on struct members


What is the simple, idiomatic way, to check that a specific struct member validates a given concept ?

I tried the following and it does not work because { T::f } yields type float&:

#include <concepts>
struct foo {
    float f;
};

// ok
static_assert(std::floating_point<decltype(foo::f)>);


template<typename T>
concept has_fp_member = requires (T t) {
  { T::f } -> std::floating_point;
};

// fails
static_assert(has_fp_member<foo>);

Where can I "remove" that useless reference being added on { T::f } ? Without making the code super ugly, adding new concepts, etc... my main requirement is that things stay readable !

e.g.

template<typename T>
concept has_fp_member = std::floating_point<decltype(T::f)>;

is very subpar, because my actual concept would check a large set of attributes, and I do not want a mess of std::foo<decltype(T::a)> && std::bar<decltype(T::b)> && ...

Note that I use float as an example but my question is about a general solution for any type / concept.


Solution

  • You might want to use macro:

    #include <concepts>
    #include <type_traits>
    
    template <class T>
    std::decay_t<T> decay_copy(T&&);
    
    #define CHECK_MEMBER(name, type) \
    { decay_copy(t.name) } -> type
    
    template<typename T>
    concept has_member_variables = requires (T t) {
      CHECK_MEMBER(f, std::floating_point);
      CHECK_MEMBER(i, std::integral);
    };
    

    Demo.