Sizeof在模板中失败,即使类型都已定义

Sizeof failing in template even though types are all defined

本文关键字:类型 定义 失败 Sizeof      更新时间:2023-10-16

好的,我正在使用g++4.8.2,下面的代码(有些长)会得到一条关于不完整类型的错误消息。我已经将代码缩减为一个较小的块,以便包含在这里,并且可以直接编译:

#include <cstdlib>
struct S
{
  void method(){}
};

template<size_t sz, size_t tot>
class genpool
{
};
template <class T>
class mempool
{
private:
  genpool<sizeof(T), 10*sizeof(T)> p;
};

template <class obj, class mthd>
class functor
{
private:
  static mempool<functor<obj, mthd> > pool;
};
template <class obj, class mthd>
mempool<functor<obj, mthd> > functor<obj, mthd>::pool;
int main()
{
  typedef void (S::*m)();
  typedef functor<S, m> fctr;
  fctr f;
}

编译器错误消息为:

g++ jj.C
jj.C: In instantiation of ‘class mempool<functor<S, void (S::*)()> >’:
jj.C:30:30:   required from ‘class functor<S, void (S::*)()>’
jj.C:37:8:   required from here
jj.C:18:17: error: invalid application of ‘sizeof’ to incomplete type ‘functor<S, void (S::*)()>’
   genpool<sizeof(T), 10*sizeof(T)> p;
                 ^
Compilation exited abnormally with code 1 at Thu Apr  9 18:50:06

显然,模板函子是在上面定义的,函子的所有参数都已显式定义。在我看来,这似乎意味着函数的sizeof应该得到很好的定义。这里有我遗漏的东西吗?

--Ron

问题是编译器试图在实例化functor<>之前先实例化mempool<>。这是因为编译器认为在functor<>本身被认为是完全定义之前,它需要能够首先定义静态成员functor<>::pool

解决方法是从静态成员函数返回mempool<> &

template <class obj, class mthd>
class functor
{
private:
  static mempool<functor> & get_pool () {
    static mempool<functor> pool;
    return pool;
  }
};
//template <class obj, class mthd>
//mempool<functor<obj, mthd> > functor<obj, mthd>::pool;

这是因为引用意味着mempool<>可以保持不完整,直到functor<>被实例化。(实际上,除非有代码实际调用模板的方法,否则模板的方法不会被实例化。)当调用静态方法时,functor<>本身是完整的,因此functor<>::get_pool中的静态对象可以被正确地实例化。

附带说明一下,将不完整类型作为参数传递给模板是可以接受的,但模板对不完整类型的实际操作有限制。如果模板只需要一个引用或指针来实例化类型,那么一切都很好。

您对functor的定义是递归的。它要求编译器在确定functor类型时知道functor类型的大小。你可以用这个代码生成完全相同的问题:

template <class A>
class B {
public:
    static const int szA = sizeof(A);
};
template <class A>
class C {
public:
    static B<C<A> > b;
};
int main() {
    C<int> c;
}

根据你的应用程序,你应该能够使用类型特征来做你想做的事情。

functor的内部声明pool时,您仍在定义functor类,因此类型functor仍然不完整。

这类似于远期申报:

class functor;
functor func; <<-incomplete here
functor *ptr; <<-pointer is fine
class functor
{
    functor func; <<-incomplete again
}; 
functor func; <<-now complete definition, ok

我认为你做不到,因为你有一个递归定义。例如,你不能这样做:

#include <cstdlib>
class B;
class A
{
    B b;
};
class B
{
    A a;
};
int main()
{
        A x;
}

唯一的解决方法是使其中一个成员成为指针而不是实例。