C++ 重载命名空间中的函数模板

C++ 重载命名空间中的函数模板,c++,templates,function,C++,Templates,Function,为什么不能用GCC4.4编译 template<typename T> class A { public: void foo () { } private: T x; }; namespace Ns { template<typename T> void do_it (A<T> a) { a.foo (); } }; template<typename T> void myfun (T x) { Ns

为什么不能用GCC4.4编译

template<typename T>
class A {
public:
    void foo () {

    }

private:
    T x;
};

namespace Ns {
template<typename T>
void do_it (A<T> a) {
    a.foo ();
}
};

template<typename T>
void myfun (T x) {
    Ns::do_it (x);
}

template<typename T>
class B {
public:
    void bar () {

    }

private:
    T x;
};

namespace Ns {
template<typename T>
void do_it (B<T> b) {
    b.bar ();
}
};

int main () {
    A<int> a;
    B<int> b;

    myfun (a);
    myfun (b); // error: no matching function call to do_it(B<int>&)

    return 0;
}
模板
甲级{
公众:
void foo(){
}
私人:
tx;
};
名称空间Ns{
模板
无效做它(A){
a、 foo();
}
};
模板
void myfun(T x){
Ns::do_it(x);
}
模板
B类{
公众:
空心条(){
}
私人:
tx;
};
名称空间Ns{
模板
无效执行(B){
b、 bar();
}
};
int main(){
A A;
B B;
myfun(a);
myfun(b);//错误:没有匹配的函数调用来执行它(b&)
返回0;
}
它必须与
do\u It
的名称空间有关。当我删除它周围的名称空间时,它会编译

背景:我正在构建一组可以与许多不同容器类一起使用的函数。为了统一处理不同的接口,我使用了独立函数,这些函数为每个容器类重载。这些函数应放在一个名称空间中,以避免全局名称空间与它们混淆


B的定义应被视为来自与a不同的头文件,因此重新排序不是一个选项。

原因是在调用点只执行ADL。其他函数查找仅在
myfun
函数模板的定义中进行

在该定义上下文中,仅声明接受
A
do\u it
重载


编辑:如果您想对此有一个标准参考,请参考[temp.dep.candidate]和[temp.res]p1。

这是一个打字错误!was被HTML.VS 2010吞没编译了上述代码,我相信这样做是正确的,但这是一个棘手的例子。问得好!VS2008也一样,我只是检查了一下。这可能是GCC中的错误,还是他们的解释与微软的不同?它在没有名称空间的情况下工作这一事实将表明它是一个bug,不是吗?@Mark如果您想考虑名称空间
Ns
中的函数,您可以从该名称空间中定义的伪类派生
B
,以便ADL可以查看
Ns
名称空间。或者,您可以将模板参数传递给将生成的专门化与
Ns
关联的
B
。例如
B
(ADLAssociator可能只是一个只存储
T;
)的小型类模板。或者将这些关联器类作为附加伪参数传递:
B
。这个有很多选择。最干净的方法似乎只是从类派生
B
,或者在
NS
中定义它。将自由函数更改为静态类成员怎么样:
名称空间NS{template struct dispatch;}
(预先声明),然后为每个新类型添加一个专门化:
名称空间NS{template struct dispatch{static void do_it(B x){x.bar()};}
,并拥有
模板void myfunc(T){Ns::dispatch::do_it(T);}
@David是的,这也行,好主意。不会依赖脆弱的ADL。@johanneschaub litb:你能详细说明这个答案吗?特别是“实例化上下文”和“定义上下文”这两个短语它们是规范中使用的标准术语吗?:-/@johanneschaub-litb:另外,你的前两个建议似乎不起作用。(参见和)不过我没有尝试第三个。