非静态成员函数的 decltype 格式不正确吗?

Is decltype of a non-static member function ill-formed?

本文关键字:不正确 格式 decltype 静态成员 函数      更新时间:2023-10-16

我不确定是否完全理解[dcl.type]/4.3

对于表达式e,用decltype(e)表示的类型定义如下:

  • [...]
  • (4.3( 否则,如果e是无括号的 ID 表达式或无括号的类成员访问,则decltype(e)e命名的实体的类型。如果没有这样的实体,或者如果e命名一组重载函数,则程序格式不正确;
  • [...]

对我来说,强调的部分都适用于id 表达式类成员访问,对吧?

玩我最喜欢的编译器,我得到以下内容。

✓ 被编译器接受

namespace N { void f() {} }
using type = decltype(N::f);
type* pf = N::f;

好吧,我猜;N::f是一个不带括号的 id 表达式,不命名一组重载函数。

✗ 被编译器拒绝

namespace N { void f() {} void f(int) {} }
using type = decltype(N::f); // error: decltype cannot resolve address of overloaded function
type* pf = N::f;

还行;N::f确实命名了一组重载函数。

✗ 被编译器拒绝

struct S { void f(){} };
using type = decltype(S::f); // error: invalid use of non-static member function 'void S::f()'
type* pf = &S::f;

哼?S::f会命名一组重载函数?


总而言之,我对[dcl.type]/4.3的理解是不是很糟糕? GCC后备箱错了吗? 两者都有? 没有? 卡穆洛克斯?

原因很简单,S::f的使用对类成员是有限制的。

[expr.prim.id]

2 表示非静态数据成员或 类的非静态成员函数只能用于:

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

最后一个项目符号(与代码相关的项目符号(仅适用于非静态数据成员。没有规定职能。

我只能推测为什么不允许这样做,尽管我之前问过这个问题。

值得注意的是,decltype(&S::f)在这里用作指向成员函数的指针类型,
除非f命名一组重载(成员(函数。

函数类型本身可以从指向成员函数类型的指针中提取。
如果成员函数符合 cv-or-ref 条件,则它具有可恶的函数类型。
这里缺少std特征 - 像Boost.CallableTraits这样的库会有所帮助。