Continuing my studies on concepts
, in the following example:
template <typename t>
concept c = requires(t p_t) {
{ p_t.f() } -> std::same_as<int>;
};
template <c t_c> int m1(t_c p_c) { return p_c.f(); }
template <c t_c> int m2() { return t_c::f(); }
struct a {
int f() { return 3; }
};
struct b {
static int f() { return 4; }
};
int main() {
std::cout << m1(a{}) << std::endl;
std::cout << m2<b>() << std::endl;
}
Shouldn’t std::cout << m2<b>() << std::endl;
to cause a compiler error, since b
does not satisfy c
?
I am using gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
, and there was no compile or runtime error.
2
Answers
This would be the correct
concept
, which cause the'a' does not satisfy 'c'
Patrick RobertsConcepts are not base classes. You do not (or at least, should not) define concepts on the basis of a function having a specific signature. Concepts verify the validity of expressions (or constant expression-y things).
And if
f
is a static member function of typeb
, and you have an instance ofb
calledt
, it is 100% legal C++ syntax to invokeb::f
via the expressiont.f()
.Therefore, the concept is satisfied.
Also, your template function
m2
is a liar. It claims that it will use a type in accord with the conceptc
, but then it does something that isn’t part ofc
.C++20 concepts cannot tell if a function constrained by a concept is lying. All it can do is check if the expressions are available.
And if the user wants to satisfy the concept via a static member function, you shouldn’t care. As long as it does what it’s supposed to do, let the user have the freedom to fulfill the condition as they see fit.