And*_*der 3 c++ templates namespaces c++11
以下是我正在使用的迭代器的简化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;
}
Run Code Online (Sandbox Code Playgroud)
代码在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必须在继续之前将所有定义添加到其符号表中.标准是指定一种方法还是另一种方法,或者该实现是否具体?也就是说,如果定义不在命名空间内,我不明白为什么这不是问题.
基本规则是,在编写时foo(/* something dependent on a template parameter*/);,普通的非限定查找foo仅考虑模板定义上下文,而ADL将同时考虑定义和实例化上下文.因此,ADL可以考虑在模板定义上下文中找不到的重载的唯一方法.
在bar(meta::meta_size_t<N-1>());,void bar(meta::meta_size_t<1>) {}不在范围内,因此可以调用的唯一方法是依赖于参数的查找,但ns不是相关的命名空间meta::meta_size_t<1>,因此您可以获得无限递归.
当你使用 ns_size_t,则ns是一个关联的命名空间,因此barADL找到第二个重载并通过重载决策选择,终止递归.
当您交换bars 的顺序时,普通的非限定查找将找到终止的情况,所以一切都很好.
MSVC因其在模板名称查找方面的不合格而闻名.
| 归档时间: |
|
| 查看次数: |
309 次 |
| 最近记录: |