以下是我在std::tuple
上使用的迭代器的简化。在其中,我在一个名称空间中定义模板化类型,并在第二个名称空间中使用它,如下所示:
namespace meta{
template<size_t> struct meta_size_t {};
}
namespace ns{
//template<size_t> struct ns_size_t {};
template <size_t N>
void bar(meta::meta_size_t<N>) {
bar(meta::meta_size_t<N-1>());
}
void bar(meta::meta_size_t<1>) {}
template<size_t N>
void foo() {
bar(meta::meta_size_t<N>());
}
}
int main(void){
ns::foo<5>();
return 0;
}
代码在MSVC2015中编译良好,但在g ++ 4.8和clang 3.5(-std = c ++ 11)中失败,达到模板的最大递归深度。请注意,如果meta::meta_size_t
替换为ns_size_t
(并且ns_size_t
的定义已取消注释),那么一切正常。
我猜测编译器会延迟meta::meta_size_t
的分辨率,直到它完成解析bar
,因为它在另一个命名空间(或沿着这些行的某些东西),并且是因此失败了,但我不确定如何解决这个问题。
在什么条件下这个问题通常会出现?有没有办法迫使编译器在namespace meta's
之前解析ns's
内容?我希望避免重复类型定义(如ns_size_t
所示)。
进一步背景:在原始代码中,bar
有一个std::tuple
参数,并使用std::get<N>(tuple)
编辑: Noobish错误。在查看了@WhozCraig提供的示例之后,我验证了代码可以通过交换两个bar
方法的顺序来修复(我假设g ++和clang按顺序搜索定义,因此永远不会注册bar的第二次重载,而MSVC必须在继续之前将所有定义添加到其符号表中。标准是指定一种方法还是另一种方法,或者该实现是否具体?也就是说,如果定义不在命名空间内,我不明白为什么这不是问题。