3
struct X
{
    void f(double) {}
    static void f(int) {}
};

int main()
{
    X x;

    auto y = x.f;
}

gcc 给出:

error: unable to deduce ‘auto’ from ‘x.X::f’

x.f是5.2.5 [expr.ref] 中记录的类成员访问 postfix-expression

它有效地说:

如果f是(可能重载的)成员函数,函数重载决议(13.3)用于确定x.f是指静态成员函数还是非静态成员函数。(来自 N3485 5.2.5.4.3 )

如何在此处应用重载解析 -x.f没有用于进行重载解析的参数列表?

还是我错过了什么?

更新:如果我将auto y = x.f行更改为expression-statement

- auto y = x.f;
+ x.f;

然后 gcc 反而抱怨:

error: statement cannot resolve address of overloaded function
4

2 回答 2

3

我认为你是对的,标准在这一点上并不精确:

[expr.ref]/4

如果 f 是(可能重载的)成员函数,则函数重载决议 (13.3) 用于确定是x.f指静态成员函数还是非静态成员函数。

正如第一个子项目符号所述:

如果它引用一个静态成员函数并且E2的类型是“参数类型列表返回T的函数”,那么E1.E2是一个左值;表达式指定静态成员函数。E1.E2的类型与E2的类型相同,即“参数类型列表返回T的函数”。

也就是说,x.f如果是静态的,可用于初始化函数 ptr f,而(请参阅以下子项目符号)如果f不是静态的,则只能在函数调用表达式中使用。

但实际上,不会执行重载决议以从函数调用表达式上下文之外的重载函数的名称中选择重载:

[over.over]/1

使用不带参数的重载函数名称在某些上下文中被解析为函数、指向函数的指针或指向重载集中特定函数的成员函数的指针。[...]所选函数的类型与上下文中所需的目标类型的函数类型相同。

也就是说,完全匹配,不调用 [over.match] 中描述的重载解决机制。因此 [expr.ref]/4 是不完整的,它没有描述您使用x.f初始化函数指针/引用的情况。

由于auto关键字未指定目标类型(或根据 [dcl.spec.auto]/6,推断类型auto失败的机制),您不能使用auto y = x.f;

  • x.f指一组重载的函数
  • 需要从这个集合中选择一个函数
  • 选择基于重载决议(在函数调用表达式中,此处不适用)或基于目标类型
  • 这里没有目标类型,或者更确切地说,目标类型等价于模板参数,因此类型推导auto失败

因此的类型x.f

  • 在函数调用的上下文中,直接参考[expr.ref]/4
  • 否则是一组重载函数,然后根据[over.over]从中选择函数,然后根据[expr.ref]/4确定类型
于 2013-05-14T12:57:52.483 回答
2

即使x.f在此上下文中只有一个有效,编译器也必须在确定函数是否为静态之前进行重载解析。

§5.2.5 « 如果 E2 是(可能重载的)成员函数,则函数重载决议(13.3)用于确定 E1.E2 是指静态成员函数还是非静态成员函数。»

重载解决机制(如 §13.3 和 §13.4 中所述)需要有效的上下文来选择正确的候选者:

§13.4.1 « 使用不带参数的重载函数名称在某些上下文中被解析为函数、函数指针或重载集中特定函数的成员函数指针 »

auto y = x.f;不是有效的解析上下文,您要么必须删除auto关键字或使用 astatic_cast来强制重载解析:

X x;

auto y = static_cast<void (&)(int)>(x.f);
y(1);

auto z = static_cast<void (X::*)(double)>(&X::f);
(x.*z)(1.);

请注意,根据第 8.3.3 节,您不能引用非静态成员,只能引用指针:

C++ 中没有“成员引用”类型

于 2013-05-14T11:48:15.823 回答