C++20 requires式(requires-expression)の単純な利用では非static/staticメンバを区別できない。requires式の本体部は評価されない(unevaluated)ため、通常コードとは異なる規則が適用されることに注意。
// staticメンバmを持つ型X struct X { static const int m = 1; }; // (非static)メンバmを持つ型Y struct Y { int m = 2; }; // staticメンバT::mを確認するコンセプト(?) template <typename T> concept HasStaticM = requires { { T::m } -> std::convertible_to<int>; }; // 式 T::m はmがstaticメンバのときのみ有効 assert( X::m == 1 ); // OK static_assert( HasStaticM<X> ); // OK // mが非staticメンバの場合は式 T::m と書けないが... assert( Y::m == 2 ); // NG: ill-formed static_assert( HasStaticM<Y> ); // OK !?
T::m
が非static/staticデータメンバのいずれかを判定するには、&T::m
の型をstd::is_member_object_pointer
メタ関数に通す。
X::m
はstaticデータメンバのため、式&X::m
は通常のポインタ型(int*
)となる。Y::m
は非staticデータメンバのため、式&Y::m
はデータメンバへのポインタ型(int X::*
)となる。
template <typename T> concept HasStaticM = requires { { T::m } -> std::convertible_to<int>; requires !std::is_member_object_pointer_v<decltype(&T::m)>; }; static_assert( HasStaticM<X> ); // OK static_assert( !HasStaticM<Y> ); // OK
C++20(N4861) 7.5.4/p2, 7.5.7/p2より引用(下線部は強調)。
id-expression:
unqualified-id
qualified-id
2 An id-expression that denotes a non-static data member or non-static member function of a class can only be used:
- as part of a class member access (7.6.1.4) in which the object expression refers to the member's class or a class derived from that class, or
- to form a pointer to member (7.6.2.1), or
- if that id-expression denotes a non-static data member and it appears in an unevaluated operand. [Example:
struct S { int m; }; int i = sizeof(S::m); // OK int j = sizeof(S::m + 42); // OK-- end example]
2 A requires-expression is a prvalue of type
bool
whose value is described below. Expressions appearing within a requirement-body are unevaluated operands (7.2).
関連URL