我在编译代码时遇到了一些问题,可以很容易地用以下代码总结出来:
template <typename _Ty>
class Foo
{
public:
using allocator_type = typename _Ty::allocator_type;
};
template <typename _Ty, typename _Alloc = std::allocator<_Ty>>
class Bar
{
public:
using allocator_type = _Alloc;
Foo<Bar<_Ty, _Alloc>> foo;
};
int main(void)
{
Foo<Bar<int>> x;
}
无法在Visual Studio中编译,但出现以下错误:
Error 1 error C2079: 'Bar<int,std::allocator<_Ty>>::foo' uses undefined class 'Foo<Bar<int,std::allocator<_Ty>>>' c:\users\duncan\desktop\test\test\main.cpp 17 1 Test
如果Foo
的成员类型为_Ty
,则显然会出现问题(出于同样的原因Foo
不能拥有Foo
类型的成员),但是这不是这里的情况,我有点困惑。更让我失望的是,如果我将foo
Bar
成员更改为指针,编译器错误就会消失。即使更加疯狂,Foo<Bar<_Ty, _Alloc>>
也可以在Bar
的成员函数中用作局部变量而没有错误。
标准中是否存在阻止此类使用的内容,或者这是Visual Studio 2013编译器的错误?我目前无法轻松访问带有GCC的编译器来测试它。这种模式似乎是值得关注的。
答案 0 :(得分:3)
您的代码无法编译,因为在实例化模板特化class Bar<int>
时,它会在Bar<int>
的定义中请求具体的class Bar<int>
对象。这是不允许的,因为在编译器看到Foo<Bar<int>> foo;
时,它对Bar<int>
一无所知(即模板特化Bar<int>
的定义不完整)。
你能做些什么就是将Bar
作为指针传递。要做到这一点,您还需要专门指定Foo
指针,如下例所示:
template <typename _Ty>
class Foo
{
public:
using allocator_type = typename _Ty::allocator_type;
};
template <typename T>
class Foo<T*>
{
public:
using allocator_type = typename T::allocator_type;
};
template <typename _Ty, typename _Alloc = std::allocator<_Ty>>
class Bar
{
public:
using allocator_type = _Alloc;
Foo<Bar*> foo;
};
或者强制创建模板特化Bar<int>
,以便编译器事先知道它:
template <typename _Ty>
class Foo
{
public:
using allocator_type = typename _Ty::allocator_type;
};
template <typename _Ty, typename _Alloc = std::allocator<_Ty>>
class Bar
{
public:
using allocator_type = _Alloc;
Foo<Bar> foo;
};
template class Bar<int>; // force create Bar<int>
还要记住:
下划线后跟大写字母留作STL使用。
Bar
的名称注入template class Bar
的定义。因此,使用内部模板定义Bar<T, Alloc>
或Bar
是相同的。