理解概念。检查成员是否是静态的

Ser*_* Pv 3 c++ templates c++-concepts c++20 c++-templates

假设我们有一个简单的概念,例如:

template <typename T>
concept MyConcept = requires {
    T::value == 42; 
};
Run Code Online (Sandbox Code Playgroud)

根据我的理解,这个概念是说,如果代码T::value == 42对于类型 T 有效,我就会通过。所以value必须是静态成员,对吗?

我有一个struct

struct Test { int value = 0; }
Run Code Online (Sandbox Code Playgroud)

和下一个模板函数

template <MyConcept T>
void call() { /*...*/ }
Run Code Online (Sandbox Code Playgroud)

当我尝试这样做时:

int main()
{
    call<Test>();
}
Run Code Online (Sandbox Code Playgroud)

有用!

问题是:它为什么有效? Test::value == 42不是该类型的有效代码Test

我找到了一种修复它的方法,例如:

template <typename T>
concept MyConcept = requires {
    *(&T::value) == 42; 
};
Run Code Online (Sandbox Code Playgroud)

它按预期“工作”:

<source>:6:20: note: the required expression '((* & T::value) == 42)' is invalid
Run Code Online (Sandbox Code Playgroud)

这个概念只适用于静态value,正如它应该的那样。但为什么会起作用呢T::value == 42

神螺栓: https: //godbolt.org/z/d3GPETEq9

UPD:+示例https://godbolt.org/z/d8qfzK9b6

Bar*_*rry 5

\n

这个概念只适用于静态值,正如它应该的那样。但为什么会起作用呢T::value == 42

\n
\n

因为规则中实际上有一个例外,您认为会导致此失败。

\n

来自[expr.prim.id.general]/3 的规则是,强调我的:

\n
\n

表示类的非静态数据成员或非静态成员函数的id 表达式只能使用:

\n
    \n
  • 作为类成员访问的一部分,其中对象表达式引用成员的类51或从该类派生的类,或者
  • \n
  • 形成指向成员的指针 ([expr.unary.op]),或者
  • \n
  • 如果该 id 表达式表示非静态数据成员并且它出现在未计算的操作数中
  • \n
\n

[示例 3

\n
struct S {\n  int m;\n};\nint i = sizeof(S::m);           // OK\nint j = sizeof(S::m + 42);      // OK\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x94结束示例]

\n
\n

第三个项目符号就在那里:T::value可用作未评估的操作数。您在需求中签入的所有表达式均未计算。因此T::value适用于非静态数据成员。

\n