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
\n\n这个概念只适用于静态值,正如它应该的那样。但为什么会起作用呢
\nT::value == 42?
因为规则中实际上有一个例外,您认为会导致此失败。
\n来自[expr.prim.id.general]/3 的规则是,强调我的:
\n\n\n表示类的非静态数据成员或非静态成员函数的id 表达式只能使用:
\n\n
\n- 作为类成员访问的一部分,其中对象表达式引用成员的类51或从该类派生的类,或者
\n- 形成指向成员的指针 ([expr.unary.op]),或者
\n- 如果该 id 表达式表示非静态数据成员并且它出现在未计算的操作数中。
\n[示例 3:
\nRun Code Online (Sandbox Code Playgroud)\nstruct S {\n int m;\n};\nint i = sizeof(S::m); // OK\nint j = sizeof(S::m + 42); // OK\n\xe2\x80\x94结束示例]
\n
第三个项目符号就在那里:T::value可用作未评估的操作数。您在需求中签入的所有表达式均未计算。因此T::value适用于非静态数据成员。