Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a C++ requires clause in a concept to require a member variable to satisfy a concept constraint?

I was watching a C++ 20 Concepts Presentation , and when attempting to reproduce the code I seem to be stuck.

I am trying to require that the root of the tree should satisfy the MyObjConcept0_, which for simplicity's sake is just an int. How come when I use this concept in the requires clause of the Tree_ concept the results are false?

I tried to copy the code directly from the presentation and still no luck. Why is the return type of the { t.root } clause an int& - I mean it makes sense, because when you access a member that way you get a reference.

So how come in the presentation at 39:00 this(same as MyObjConcept0_) requires clause passes?

Did something change in the standard from the point of this presentation or am I blindly missing something?

#include <concepts>
#include <functional>

// Type is an int
template<typename T>
concept MyObjConcept0_ = std::same_as<T,int>;

// Type is any type that decays to int
template<typename T>
concept MyObjConcept1_ = std::same_as<std::decay_t<T>,int>;

// Type is an int&
template<typename T>
concept MyObjConcept2_ = std::same_as<T,int&>;



template<typename T>
concept Tree_ = requires (T t) {
    { t.root } -> MyObjConcept0_;          // does not work : This is the concept I want to use  
    { t.root } -> MyObjConcept1_;          // works but will pass for int and int& : unsafe
    { t.root } -> MyObjConcept2_;          // works but checks that t.root is an int&
    std::same_as<decltype(t.root),int>; // works: verbose and not a concept
};

template<MyObjConcept0_ MyObjConcept0T>
struct tree {
    MyObjConcept0T root;
};

static_assert(Tree_<tree<int>>);
like image 955
Big Teeny Avatar asked Oct 16 '22 01:10

Big Teeny


1 Answers

The compound-requirement

{ e } -> Concept;

means that e must be a valid expression and Concept<decltype((e))> must hold. Note the double parentheses, this is important. Let's just take a simpler tree, I don't know why this needs to be a template:

struct X {
    int root;
};

X t;

While decltype(t.root) is int (the declared type of that member variable is int), decltype((r.root)) is int& (because it is an lvalue of type int, hence int&). As a result:

template <typename T>
concept Tree = requires(T t) {
    { t.root } -> std::same_as<int&>;
};

Tree<X> holds - because t.root is an lvalue of type int.


clang simply gets this wrong. It does not implement P1084, this is #45088.

like image 114
Barry Avatar answered Nov 15 '22 10:11

Barry