C++ 重载命名空间中的函数模板
为什么不能用GCC4.4编译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
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:另外,你的前两个建议似乎不起作用。(参见和)不过我没有尝试第三个。