为什么结构必须与模板类位于同一名称空间中才能编译?

时间:2014-12-30 19:24:53

标签: c++ templates gcc mingw

问题的标题并没有透露太多关于我的问题,但我试图用一个短语来解释这个问题。这是问题,我在Windows中使用MinGW和Linux中使用GCC编译的应用程序中有类似的代码结构。 Visual Studio不会出现任何问题。结构如下:

#include <iostream>

namespace idb
{
    class Wrapper
    {
    public:
        template<typename S>
        void boo(S& s)
        {
            bind(s);
        }
    };
}

namespace idb // <- if this namespace changes, code explodes
{
    struct Fulalas
    {
        int x;
    };
}

namespace idb
{
    void bind(idb::Fulalas f)
    {
        std::cout << f.x << std::endl;
    }
}

namespace app
{
    class Foo
    {
    public:
        void func()
        {
            idb::Fulalas f;
            f.x = 5;
            w.boo(f);
        }

    private:
        idb::Wrapper w;
    };
}

int main()
{
    app::Foo f;
    f.func();
    return 0;
}

问题是为什么在GCC / MinGW中将idb::Fulalas更改为aaa::Fulalas(或任何所需的名称)会产生以下错误:

..\namespace\main.cpp: In instantiation of 'void idb::Wrapper::boo(S&) [with S = aaa::Fulalas]':
..\namespace\main.cpp:41:11:   required from here
..\namespace\main.cpp:11:10: error: 'bind' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
    bind(s);
          ^
..\namespace\main.cpp:26:7: note: 'void idb::bind(aaa::Fulalas)' declared here, later in the translation unit
  void bind(aaa::Fulalas f)

2 个答案:

答案 0 :(得分:5)

它与结构无关。

关于bind和参数依赖查找。

bind使用不合格,因此在关联的命名空间中查找。如果struct与绑定重载不在同一名称空间中,则不会看到/考虑它。

答案 1 :(得分:2)

在表达式

bind(s)

名称bind是依赖的,因为参数s的类型为S,这是一个模板参数。依赖名称在模板实例化时绑定。当您致电

时会发生这种情况
w.boo(f);

然后使用类型boo实例化S = idb::Fulalas。解析从属名称时,会从两个来源考虑声明:

  
      
  • 在模板定义时可见的声明。
  •   
  • 来自名称空间的声明与函数参数的类型相关联   实例化上下文(14.6.4.1)和定义上下文。
  •   

([temp.dep.res])

因此,如果在模板定义点之后但在实例化之前声明了名称,那么它只能由ADL找到,而不能通过普通的非限定名称查找。普通的非限定查找只能找到在模板定义点可见的名称,而不是在实例化时。因此,如果Fulalas未在与bind相同的命名空间中声明,则ADL将找不到idb::bind的声明,并且名称查找将完全失败。