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.
CodePudding user response:
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);
};
CodePudding user response:
Here's a partial solution but I would like to find something better (inspired from an answer to this question which has been removed)
auto prvalue(auto&& arg) { return arg; }
template<typename T>
concept has_fp_member = requires (T t) {
{ prvalue(T::f) } -> std::floating_point;
};
static_assert(has_fp_member<foo>);
It only supports cases where the member is copy-constructible though.