与我的期望相反,该程序有效:

#include <iostream>


namespace a { struct item{}; }
namespace b { struct item{}; }


template<typename T>
void func(T t) { do_func(t); }


int main()
{
    func(a::item{});
    func(b::item{});
}


namespace a { void do_func(item) { std::cout << "a::func\n"; } }
namespace b { void do_func(item) { std::cout << "b::func\n"; } }

输出:
a::func
b::func

在线编译器的验证:
  • gcc 4.8
  • clang 3.4

  • 如果func<T>的实例出现在main的主体中,那么我希望尚未声明a::do_funcb::do_func

    这怎么工作?

    更新资料

    根据@Marc Claesen的说法,上述方法起作用的原因是:



    但是,为什么这段代码不起作用:
    #include <iostream>
    
    template<typename T>
    void func(T t) { do_func(t); }
    
    int main()
    {
        func(1);
    }
    
    void do_func(int) { std::cout << "do_func(int)\n"; }
    

    参见gcc-4.8:
    error: 'do_func' was not declared in this scope,
    and no declarations were found by argument-dependent
    lookup at the point of instantiation [-fpermissive]
    

    clang++ 3.4:
    error: call to function 'do_func' that is neither
    visible in the template definition nor found by
    argument-dependent lookup
    

    因此,似乎需要功能模板和ADL的组合才能使其正常工作。

    但是,我不明白为什么会这样。

    最佳答案

    之所以起作用,是因为有两个有趣的事情:

  • 两阶段名称查找,用于查找从属名称。
  • 和参数依赖查找(ADL)。

  • 看看这个:
  • The Dreaded Two-Phase Name Lookup

  • 简而言之,do_func是一个从属名称,因此在第一阶段(当仅分析文件但未实例化功能模板时),编译器执行而不是解析名称do_func,它仅检查语法并认为是有效的函数调用。就这些。在第二阶段中,实例化功能模板(因此知道T)时,解析名称do_func,这时它还使用ADL查找名称。

    请注意,ADL仅适用于用户定义的类型。它不适用于内置类型,这就是第二个代码(即func(1))不起作用的原因!

    关于c++ - 如果尚未声明我的函数,编译器为什么会找到它?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16623408/

    10-11 01:04