What's the best way to express concept requirements for data members in a concept?

Viewed 116

what's the best way to define a concept with a nested concept requirements for a data member of the type? Something along these lines:

template<typename T>
concept MyConcept = requires(T a) {    
    {a.something} -> std::integral;
};

This doesn't work because a.something is picked up as a reference (delctype((a.something))). The best I came up with that works is something like this that forces an rvalue:

constexpr auto copy = [](auto value) { return value; };

template<typename T>
concept MyConcept = requires(T a) {    
    {copy(a.something)} -> std::integral;
};

Do I have any better options?

2 Answers

The downside of copy is that it can create false positives for you. A reference member will decay to a value. The only way to ensure the actual type of the member is analyzed, is to write an explicit nested requirement.

template<typename T>
concept MyConcept = requires(T a) {    
    requires std::integral<decltype(a.something)>;
};

For cases like this, it'd be pretty easy to create a concept specifically for references to integral:

template<typename T>
concept integral_ref = std::is_reference_v<T> && std::integral<std::remove_reference_t<T>>;

You can then use integral_ref directly.

Indeed, you can even create generic a reference_trait that works for any unary, boolean type traits that expect object types:

template<typename T, template<typename> class Trait>
concept reference_trait = std::is_reference_v<T> && Trait<std::remove_reference_t<T>>::value;

template<typename T>
concept MyConcept = requires(T a) {    
    {a.something} -> reference_trait<std::is_integral>;
};
Related