函数对象如何影响重载决策?

时间:2012-08-29 03:42:05

标签: c++ c++11 overload-resolution function-object

在重载解析期间,函数对象是否与常规函数区别对待?如果是这样,怎么样?

我遇到了以下情况:用等效可调用函数对象替换函数改变了代码的含义:

#include <iostream>

namespace N
{
    enum E { A, B };

    void bar(E mode) { std::cout << "N::bar\n"; }
}

template <typename... Args>
void bar(Args&&... args) { std::cout << "global bar\n"; }

int main()
{
    bar(N::A);
}

这里的输出是“N :: bar”。到目前为止,非常好:ADL找到N :: bar,N :: bar和全局条都是精确匹配,N :: bar是首选,因为它不是模板。

但是如果我将全局条改变为函数对象,就像这样:

#include <iostream>

namespace N
{
    enum E { A, B };

    void bar(E mode) { std::cout << "N::bar\n"; }
}

struct S
{
    template <typename... Args>
    void operator()(Args&&... args) { std::cout << "global bar\n"; }
};
S bar;

int main()
{
    bar(N::A);
}

输出现在是“全球栏”。为什么不同?

2 个答案:

答案 0 :(得分:12)

这里重要的一点是,如果查找确定名称​​是函数调用中的函数,则ADL才会启动。在第二种情况下,bar被发现是对象而不是函数,因此表达式bar(N::A)不是函数调用,而是{{1}的应用程序}到对象operator()。因为它不是函数调用,所以ADL不会启动,并且不会考虑bar

  

3.4.1 / 3

     

3.4.2中描述了用作函数调用的后缀表达式的非限定名称的查找。 [注意:为了确定(在解析期间)表达式是否是函数调用的后缀表达式,通常的名称查找规则适用。 3.4.2 [ADL] 中的规则对表达式的句法解释没有影响。

另一种看待它的方法是注意ADL会将新函数添加到重载函数集,但在第二个示例中没有这样的集:查找查找对象和成员该对象被称为。

答案 1 :(得分:4)

见3.4.2p3,其中说

  

设X是由非限定查找(3.4.1)生成的查找集,并且让Y是由参数相关查找生成的查找集(定义如下)。如果X包含

     
      
  • ...
  •   
  • 既不是函数也不是函数模板的声明
  •   
     

然后Y是空的。

如果没有这样的规则,你是对的:ADL会将你的其他函数添加到重载集中。事实上,13.3.1.1p1依赖于此:它有两个分支;一个用于函数调用表达式,其中操作数表示一个类对象,另一个用于操作数表示一个或多个函数或函数模板。