包含类类型作为模板参数的成员

时间:2014-08-09 08:29:29

标签: c++ visual-c++

我在编译代码时遇到了一些问题,可以很容易地用以下代码总结出来:

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的编译器来测试它。这种模式似乎是值得关注的。

1 个答案:

答案 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;
};

LIVE DEMO

或者强制创建模板特化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>

LIVE DEMO

还要记住:

  • 下划线后跟大写字母留作STL使用。

  • Bar的名称注入template class Bar的定义。因此,使用内部模板定义Bar<T, Alloc>Bar是相同的。

相关问题