即使类型已定义,模板中的大小也会失败

时间:2015-04-10 01:06:52

标签: c++ templates gcc sizeof

好的,我正在使用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函数。我在这里找不到什么东西吗?

- 罗恩

4 个答案:

答案 0 :(得分:6)

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

解决方法是从静态成员函数返回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中的静态对象可以正确实例

  

<子>   作为旁注,将不完整类型作为参数传递给模板是可以接受的,但模板对不完整类型实际执行的操作有限制。如果模板只需要一个引用或指向其实例化类型的指针,那么一切都很好。   

答案 1 :(得分:1)

您对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;
}

根据您的应用程序的不同,您应该可以使用type traits执行所需的操作。

答案 2 :(得分:1)

当您在pool 中声明functor 时,您仍在定义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

答案 3 :(得分:0)

我认为你不能这样做,因为你有一个递归的定义。例如,您无法执行此操作:

#include <cstdlib>

class B;

class A
{
    B b;
};

class B
{
    A a;
};

int main()
{
        A x;
}

唯一的出路是让其中一个成员成为指针而不是实例。