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

时间:2017-06-12 01:02:43

标签: c++ c++11 templates namespaces argument-dependent-lookup

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";
    }
}

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

给出以下测试代码(on 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
}

我假设argument dependent lookup会通过参数类型{{1}的最内层封闭命名空间(found)找到notfoundN }。

然而:

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) { ^~~~~~~~ 电话后)notfound<bool, N::C>(object)的错误相同

为什么通过ADL找不到notfound<bool>(object)

背景:我为某个包装器类实现了notfound函数,总体上与std::get(std::tuple)相似。作为实现细节的包装类存在于某个名称空间get中。我不希望图书馆的用户出于显而易见的原因指定lib::aspect::part::impl

1 个答案:

答案 0 :(得分:8)

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

来自标准:$17.8.1/8 Explicit template argument specification [temp.arg.explicit]

(强调我的)

  

[注意:对于简单的函数名称,应用依赖于参数的查找   即使函数名称在范围内不可见   呼叫。这是因为调用仍然具有a的句法形式   函数调用([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
}
     

- 结束示例] - 结束注释]

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

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&
}

LIVE