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

Members with the containing class type as a template argument

本文关键字:参数 成员 包含类 类型      更新时间:2023-10-16

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

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:usersduncandesktoptesttestmain.cpp  17  1   Test

如果Foo具有类型_Ty的成员(出于同样的原因Foo不能具有类型Foo的成员),这显然是一个问题,但由于这里不是这种情况,我有点困惑。更让我吃惊的是,如果我将Barfoo成员改为指针,编译器错误就会消失。更疯狂的是,Foo<Bar<_Ty, _Alloc>>可以用作Bar成员函数中的局部变量而不会出错。

在标准中是否有任何东西阻止这种使用,或者这是Visual Studio 2013编译器的错误?我目前没有很容易地访问与GCC的编译器来测试它。这种模式似乎是值得遵循的。

你的代码没有编译,因为在模板专门化class Bar<int>的实例化时,它要求在class Bar<int>的定义内的具体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是相同的。