简体   繁体   English

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

[英]How do function objects affect overload resolution?

Are function objects treated differently from regular functions during overload resolution? 在重载解析期间,函数对象是否与常规函数区别对待? If so, how? 如果是这样,怎么样?

I have run into the following case where replacing a function with an equivalently-callable function object changed the meaning of the code: 我遇到了以下情况:用等效可调用函数对象替换函数改变了代码的含义:

#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);
}

Here the output is "N::bar". 这里的输出是“N :: bar”。 So far, so good: N::bar is being found by ADL, both N::bar and the global bar are exact matches, and N::bar is preferred because it's not a template. 到目前为止,非常好:ADL找到N :: bar,N :: bar和全局条都是精确匹配,N :: bar是首选,因为它不是模板。

But if I change the global bar to be a function object, like so: 但是如果我将全局条改变为函数对象,就像这样:

#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);
}

The output is now "global bar". 输出现在是“全球酒吧”。 Why the difference? 为什么不同?

The important bit here is that ADL only kicks in if lookup determines that the name is a function in the function call. 这里重要的一点是,如果查找确定名称函数调用中的函数,则ADL仅启动。 In the second case, bar is found to be an object and not a function, so the expression bar(N::A) is not a function call, but the application of operator() to the object bar . 在第二种情况下, bar被发现是一个对象而不是一个函数,因此表达式bar(N::A)不是函数调用,而是operator()应用于对象bar Because it is not a function call, ADL does not kick in and N::bar is not considered. 因为它不是函数调用,所以ADL不会启动并且不考虑N::bar

3.4.1/3 3.4.1 / 3

The lookup for an unqualified name used as the postfix-expression of a function call is described in 3.4.2. 查找用作函数调用的后缀表达式的非限定名称在3.4.2中描述。 [ Note: For purposes of determining (during parsing) whether an expression is a postfix-expression for a func- tion call, the usual name lookup rules apply. [注意:为了确定(在解析期间)表达式是否是函数调用的后缀表达式,通常的名称查找规则适用。 The rules in 3.4.2 [ADL] have no effect on the syntactic interpretation of an expression. 3.4.2 [ADL]中的规则对表达式的句法解释没有影响。

Another way to look at it is to notice that ADL will add new functions to the set of overloaded functions , but in the second example there is no such set: lookup finds an object and a member of the object is called. 查看它的另一种方法是注意ADL将向重载函数集添加新函数,但在第二个示例中没有这样的集合:lookup查找对象并调用对象的成员。

See 3.4.2p3, which says 见3.4.2p3,其中说

Let X be the lookup set produced by unqualified lookup (3.4.1) and let Y be the lookup set produced by argument dependent lookup (defined as follows). 设X是由非限定查找(3.4.1)产生的查找集,并且让Y是由参数相关查找产生的查找集(定义如下)。 If X contains 如果X包含

  • ... ...
  • a declaration that is neither a function or a function template 既不是函数也不是函数模板的声明

then Y is empty. 那么Y是空的。

If there would not be such a rule, you are right: ADL would add your other function to the overload set. 如果没有这样的规则,你是对的:ADL会将你的其他函数添加到重载集中。 In fact, 13.3.1.1p1 relies on this: It has two branches; 事实上,13.3.1.1p1依赖于此:它有两个分支; one for function call expressions where the operand denotes a class object, and another one where the operand denotes one or more functions or function templates. 一个用于函数调用表达式,其中操作数表示一个类对象,另一个用于操作数表示一个或多个函数或函数模板。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM