In the following code class A has a private member function f. I want to write a static assertion that will check whether this function is accessible from the current context (as was suggested in the comment to this question).
There are 3 similar cases all based on requires-expression:
class A{ void f(); };
// #1: accepted by all
static_assert( { return requires(decltype(x) a){ a.f(); }; }(A{}) );
// #2: rejected by Clang:
static_assert( { return requires(A a){ a.f(); }; }(nullptr) );
// #3: rejected by all
static_assert( { return requires(A a){ a.f(); }; }(nullptr) );
The case #3 (and #2 in Clang) is rejected with the error:
error: 'f' is a private member of 'A'
Demo: https://gcc.godbolt.org/z/Mxs4P7x8s
Why does requires-expression behave differently in template and not-template (cases #1 and #3)? Which compiler is right in #2?
Whilst https://eel.is/c++draft/expr.prim.req.general#1 describes that
the grammar of a requires-expression
allows requires-expressions containing arbitrary expressions that do not necessarily depend on template arguments, meaning the following is well-formed:
Thus, for a requires-expression that is declared outside of a templated entity, the same rules as for any expression applies, and
#3is thus correctly rejected by all compilers (access checking control is not waived in the context of expressions in requires-expressions).#1is also correctly implemented by all compilers, as per https://eel.is/c++draft/expr.prim.req.general#5.sentence-2:... as
a.f();in the constraint expression for the genericasubstituted as being of typeAresults in an invalid expression, asf()is private and not visible.Finally,
#2is IFNDR as per https://eel.is/c++draft/expr.prim.req.general#5.sentence-6:We could likewise argue that it is IFNDR as per https://eel.is/c++draft/temp.res.general#6.4:
Thus,
#2is correctly implemented by all compilers, but it's arguably always nice when compilers actually do diagnose IFNDR violations, so a usability star for Clang.