具有std :: function的ADL:是否可以通过std :: function的参数列表中的类型找到采用std :: function对象的函数?

use*_*653 6 c++ language-lawyer argument-dependent-lookup std-function

考虑以下代码片段:

#include <functional>

namespace ns {
    struct Arg{};
    using Func = std::function<int(Arg)>;

    Func operator+(Func lhs, Func rhs) {
        return [lhs, rhs](Arg arg) {
            return lhs(arg) + rhs(arg);
        };
    }
}

int main() {
    ns::Func foo = [](ns::Arg i) {return 5;};
    ns::Func bar = [](ns::Arg i) {return 2;};
    auto foobar = foo + bar;
    return foobar(ns::Arg());
}
Run Code Online (Sandbox Code Playgroud)

上面的代码使用各种编译器进行编译。相反,以下代码段不会编译。唯一的区别是FuncArgvs int)内部使用的参数类型:

#include <functional>

namespace ns {
    using Func = std::function<int(int)>;

    Func operator+(Func lhs, Func rhs) {
        return [lhs, rhs](int i) {
            return lhs(i) + rhs(i);
        };
    }
}

int main() {
  ns::Func foo = [](int i) {return i + 5;};
  ns::Func bar = [](int i) {return i * 2;};
  auto foobar = foo + bar; // BANG! Error here!
  return foobar(2);
}
Run Code Online (Sandbox Code Playgroud)

我理解后一个版本的错误:被调用operator+是在名称空间中定义的,因此,如果未明确指定名称空间,则不会找到该被调用对象。依赖于参数的查找在这里无济于事,因为operator+定义ns的参数名称空间()与参数的类型(std::function定义于namespace stdusing声明与此无关)。

但是,为什么operator+Func有争议的情况下找到正确的答案ns::Arg呢?的名称空间Func未更改。Arg根据C ++标准使用的代码是否有效?

Sto*_*ica 7

使用Arg的代码根据C ++标准是否有效?

它是。根据[basic.lookup.argdep / 2.2],ADL的关联名称空间包括任何专门化模板参数的关联名称空间。

...此外,如果T是类模板专业化,则其关联的名称空间和类还包括:与为模板类型参数(不包括模板模板参数)提供的模板参数的类型相关联的名称空间和类;任何模板模板参数为其成员的名称空间;以及用作模板模板参数的任何成员模板都是成员的类。[?注意:非类型模板参数不会影响关联的名称空间。?-?注意事项?]

std::function<int(Arg)>是类模板专门化,并且ns与其参数之一相关联。因此ns,包含在operator+ADL 搜索的名称空间集中。

存在此规则是为了使可重用组件更有用。这个想法是允许一个库公开一个以a std::unique_ptr<ns::Foo>作为句柄类型的API ,并让ADL ns在出现一个句柄时从中选取正确的函数。