使用模板化类型和命名空间的"不完整类型无效使用
"Invalid use of incomplete type" using templated type and namespaces
以下是我在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
,因为它在另一个命名空间(或沿着这些行),因此失败,但我不确定如何解决这个问题。
这个问题通常在什么情况下出现?是否有任何方法强制编译器在ns's
之前解析namespace meta's
内容?我希望避免重复类型定义(如ns_size_t
所示)。
进一步上下文:在原始代码中,bar
有一个std::tuple
形参,并使用std::get<N>(tuple)
Edit: 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
是一个关联的名称空间,因此ADL找到bar
的第二个重载并由重载解析选择,从而终止递归。
当您交换bar
s的顺序时,那么普通的非限定查找将找到终止情况,因此一切正常。
MSVC以其在模板名称查找方面的不一致性而闻名。
- 具有引用返回类型的重写方法上的协变返回类型无效
- 使用 std::future 的不完整类型无效使用
- 类指针和类指针指向二进制运算符+的类型无效的操作数
- 静态类模板成员:将"sizeof"应用于不完整类型无效
- 数组的类型无效
- 返回并强制转换数组指针(错误:数组下标的类型..无效)
- 错误:数组下标'double*[double]'的类型无效
- 数组下标错误的类型无效
- 协变返回类型无效的转换错误
- 在代码块错误中收到此错误:数组下标'main()::fields[int]'的类型无效
- 3 错误:错误:未在此范围内声明'Entry'。错误:模板参数 1 无效。错误:令牌之前声明中的类型无效'('
- 类成员数组的实现:数组下标的类型无效
- 别名模板、部分专用化和无效参数类型无效
- 数组下标'int [5][float]'的类型无效
- 数组下标的类型无效
- 是否存在对类型名称有效但对基本类型无效的语言构造
- 编译错误 - 数组下标'char[int]'的类型无效
- 使用指向结构数组的指针的参数类型无效
- 使用类模板初始化下标重载函数中的引用类型无效
- 对模板和decltype使用不完整类型无效