对于带有附加(非推断)模板参数的函数,ADL是否失败(或未完成?)

Dan*_*our 9 c++ templates namespaces argument-dependent-lookup c++11

namespace N {
    class C {};

    template<typename X>
    char const * found(X && x) {
        return "found";
    }

    template<typename, typename X>
    char const * notfound(X && x) {
        return "not found";
    }
}
Run Code Online (Sandbox Code Playgroud)

这定义了一个N带有类C和两个函数模板的命名空间.found有一个模板参数,可以从函数参数中推导出来.notfound有一个额外的模板参数,无法推断.

给出以下测试代码(在ideone上):

#include <iostream>
int main() {
    N::C object;
    std::cout
        << found(object) << std::endl
        << notfound<bool>(object) << std::endl  // ERROR
        << notfound<bool, N::C>(object) << std::endl; // ERROR
}
Run Code Online (Sandbox Code Playgroud)

我假设依赖参数的查找将同时找到foundnotfound通过N参数类型的最内层封闭命名空间(即)N::C.

然而:

prog.cpp: In function ‘int main()’:
prog.cpp:21:6: error: ‘notfound’ was not declared in this scope
   << notfound<bool>(object) << std::endl
      ^~~~~~~~
prog.cpp:21:6: note: suggested alternative:
prog.cpp:12:15: note:   ‘N::notfound’
  char const * notfound(X && x) {
               ^~~~~~~~
Run Code Online (Sandbox Code Playgroud)

(notfound<bool, N::C>(object)注释掉notfound<bool>(object)通话后的同样错误)

为什么notfound不通过ADL找到?


背景:我正在get为一些包装类实现一个函数,所有这些都相对类似std::get(std::tuple).包装类是一个实现细节,它位于某个命名空间中lib::aspect::part::impl.我不希望库的用户using lib::aspect::part::impl::get出于明显的原因进行指定.

son*_*yao 8

因为函数调用具有显式指定的模板参数的函数模板,所以必须通过普通查找找到模板的名称; 直到那个ADL无法启动.

来自标准:$ 17.8.1/8显式模板参数规范[temp.arg.explicit]

(强调我的)

[注意:对于简单的函数名称,即使函数名称在调用范围内不可见,依赖于参数的查找也适用.这是因为调用仍然具有函数调用的句法形式([basic.lookup.unqual]).但是当使用具有显式模板参数的函数模板时,除非在调用点处有一个具有该名称的函数模板,否则调用没有正确的语法形式.如果看不到这样的名称,则调用语法不完善,并且参数依赖查找不适用.如果某些此类名称可见,则应用依赖于参数的查找,并且可以在其他名称空间中找到其他函数模板.[例如:

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);          // ill-formed: not a function call
  A::f<3>(b);       // well-formed
  C::f<3>(b);       // ill-formed; argument dependent lookup applies only to unqualified names
  using C::f;
  f<3>(b);          // well-formed because C?::?f is visible; then A?::?f is found by argument dependent lookup
}
Run Code Online (Sandbox Code Playgroud)

- 结束例子] - 结束说明]

最后一句给出了可能的解决方法; 您可以在任何位置添加函数模板的声明,以使名称对于被调用是可见的.例如

template<typename>
void notfound();

int main() {
    N::C object;
    std::cout
        << found(object) << std::endl
        << notfound<bool>(object) << std::endl
        << notfound<bool, N::C&>(object) << std::endl; // btw the 2nd template argument should be N::C&
}
Run Code Online (Sandbox Code Playgroud)

生活

  • 哇,这很有帮助.我在库的全局命名空间中添加了`template <typename ...,typename> void notfound();`.(非推断的`typename ...,typename`作为模板参数应该不可能实例化IIRC) (2认同)