使用concept是否允许对非静态成员函数使用decltype?
decltype(T::func)在concept中的合法性疑问 我了解到对于拥有非静态成员函数func的类X,C++标准不允许编写decltype(X::func),按预期下面的程序应该报错(比如提示“invalid use of non-static member function”),但实际在GCC、Clang、MSVC三大编译器中都能编译通过:
#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>; }
查阅标准中expr.prim.id相关条款后,该程序似乎属于格式错误,编译器应当发出诊断,但目前没有编译器报错。想请教:像示例中这样在concept里使用decltype(T::func)是否让程序合法?还是说程序仍属格式错误,只是三大编译器都存在实现问题?
结论
程序仍属于格式错误,三大编译器的行为不符合C++标准要求。
标准依据
根据C++标准中关于expr.prim.id(主表达式中的标识符)的规定:引用非静态成员函数时,不能直接用X::func这种形式来获取其类型——非静态成员函数的标识符没有独立的函数类型,它必须与具体的类实例关联(除非是在声明指向成员函数的指针的语境中)。
decltype(T::func)这种写法,本质是试图获取未绑定的非静态成员函数的类型,这在标准中是明确禁止的,属于格式错误(ill-formed),编译器必须发出诊断信息。
编译器通过的原因
这属于编译器的实现疏漏。尽管concept是C++20的新特性,但它并未改变非静态成员函数的引用规则。编译器可能在处理concept的约束表达式时,错误地将decltype(T::func)推导为普通函数类型,或是放宽了对非静态成员函数标识符的检查逻辑,但这并不符合标准的要求。
正确的写法
如果要检查类T是否拥有签名为int(int)的非静态成员函数func,应当使用指向成员函数的指针类型来匹配:
template <typename T> concept test = std::same_as<decltype(&T::func), int (T::*)(int)>;
这种写法既符合标准规定,也能正确完成类型检查。
内容的提问来源于stack exchange,提问作者user21834971

