以下是我在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和铛3.5(-std = C++ 11)通过达到模板的最大递归深度。请注意,如果meta::meta_size_t
被替换为ns_size_t
(并且ns_size_t
的定义未被注释),那么一切正常。
我推测,编译器延缓meta::meta_size_t
分辨率,直到它完成解决bar
,因为它是在另一个命名空间(或东西沿着这些线路),并因此失败了,但我不知道如何解决这个问题。
在什么情况下会出现这个问题?有没有办法强制编译器在ns's
之前解析namespace meta's
的内容?我想避免重复类型定义(以ns_size_t
为例)。
此外上下文:在原始代码,bar
具有std::tuple
参数,并进行调用以使用std::get<N>(tuple)
编辑一个重载的函数: Noobish错误。查看@WhozCraig提供的示例后,我验证了可以通过交换两个bar
方法的顺序来修复代码(我假定g ++和clang按顺序搜索定义,因此永远不会注册第二个过载条,而MSVC必须在继续之前将所有定义添加到其符号表中)。标准是指定一种方法还是另一种方法,还是具体实现?也就是说,如果定义不在命名空间内,我不明白为什么这不是问题。
第二个'bar'应该是专业吗?无论如何,你可以转发 - 声明模板,实现重载,然后实现实际的递归模板,并且它应该被编译。 [见它活着](http://ideone.com/2OQJ2G)。 – WhozCraig
您的模板递归**是**无限的。 '虚空栏(... ...)'需要'无效栏(... ...),永远。 –
@WhozCraig第二个栏是元组迭代器的停止条件(从某种意义上说,是的,专业化,但不符合将代码调整为特定类型的传统意图,而仅仅是作为控制流的手段) –