我开始知道对于一个成员函数名为
X
的类func
,c++标准不允许我们写decltype(X::func)
。因此,我预计下面给出的程序会产生类似invalid use of non-static member function
的错误。但令我惊讶的是,程序编译所有3个编译器。
#include <iostream>
#include <type_traits>
#include <concepts>
template < typename T >
concept test = std::same_as <decltype(T::func), int(int) >;
struct D
{
int func(int);
};
int main()
{
std::cout << test<D>;
}
以上程序由所有3个编译器编译。通过查看 [expr.prim.id],程序似乎格式不正确并且应该发出诊断。但是没有一个编译器提供任何错误。那么,以程序中显示的方式使用
concept
是否使程序格式正确,或者它仍然格式错误并且所有编译器都错了?
以程序中显示的方式使用概念是否使程序合式
由于[temp.constr.normal],程序格式错误,无需诊断:
表达式 E 的范式是约束 (13.5.2),定义如下:
- 概念标识 C 的范式
是约束表达式的范式 C的,将参数中的A1,A2,...,An替换为C各自的模板参数后 每个原子约束中的映射。 如果任何此类替换导致无效类型或表达式, 程序格式错误;无需诊断。
(强调我的)
并且由于概念定义右侧的
constraint-expression
无效,因此从上面引用的参考文献可以得出我们有 IFNDR。
所有的编译器都错了吗?
不需要编译器来发出诊断信息。
在约束满足检查期间的替换失败不会导致程序格式错误;它只会导致不满足约束。此处标准的相关文本是 [temp.constr.atomic]/3:
为了确定原子约束是否满足,首先将参数映射和模板参数代入其表达式。如果替换导致无效类型或表达式,则不满足约束。否则……
根据 [temp.names]/9,要确定
test<D>
的值,我们首先需要将 test
的约束表达式简化为其 normal 形式。为了方便起见,我们假设same_as<T, U>
被定义为std::is_same_v<T, U>
(实际上它略有不同,但这并不影响这个答案)。
标准化
test
的约束表达式导致具有映射 [std::is_same_v<T, U>
-> T
, decltype(T::func)
-> U
] 的原子约束 int(int)
。请注意,参数映射表示完全有效的类型(一个依赖),因此 [temp.constr.normal]/1.4(IFNDR 案例)不适用。
仅当
D
替换为 (test
's) T
时才形成无效表达式,根据上面引用的文本,这仅意味着 test<D>
是 false
,并且程序是合式的.
根据 C++ 标准,您提供的程序不应编译无误。尽管您使用的编译器可能存在允许这种用法的错误或非标准扩展,但不建议依赖此类行为,因为它可能导致代码不可移植并且可能无法按预期工作。