On Sat, 12 Oct 2024 at 14:05, Robin Savonen Söderholm via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hi!
I can't seem to find any information about how constraints and class access specifiers could work together. Currently it seems like concepts are always evaluated from "outside" a class (i.e. only public fields and methods affect the evaluation of the constraint).

Correct. That's essential to be able to cache the result, you don't want foo<T> to mean different things depending on where the first check happens, and you don't want the result to not be memoized (for performance during compilation).

 
E.g. for example:
```c++

#include <concepts>
#include <utility>

class clazz_with_protected_ctor {
protected:
  explicit clazz_with_protected_ctor(int) {}
};

template <typename T>
struct clazz_wrapper: private T {
 template <typename... Ts>
   requires(std::constructible_from<T, Ts&&...>) explicit clazz_wrapper(Ts&&... args) : T(std::forward<T>(args)...) {}
};

void foo() {
// Generates compile-error since the constraint for the constructor can't see the protected constructor
auto my_wrapper = clazz_wrapper<clazz_with_protected_ctor>(1);
}
```

I wonder if not the above code should actually be a sensible piece of code (especially with CRTP-based API:s), and it may be needed that constraints are evaluated from the context that they are used.

Inheritance is an incredibly strong coupling, the strongest in C++. It doesn't really make sense to be inheriting from types where you don't know whether you can use a protected (or private, via friendship) API. Either inherit from arbitrary types provided as template args and rely on the members you need being public, or don't inherit.




// Robin
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals