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>>);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With