自动将类定义与声明分开?

我使用的库几乎完全由头文件中的模板类和函数组成,如下所示:

I am using a library that consists almost entirely of templated classes and functions in header files, like this:

// foo.h
template<class T>
class Foo {
  Foo(){}
  void computeXYZ() { /* heavy code */ }
};
template<class T>
void processFoo(const Foo<T>& foo) { /* more heavy code */ }

现在这很糟糕,因为每当我包含其中一个头文件时编译时间都难以忍受(实际上我在我的每个编译单元中都包含了许多头文件).

Now this is bad because compile times are unbearable whenever I include one of those header files (and actually I include many of them in each of my compilation units).

因为作为模板参数我只使用一两种类型,无论如何我打算为每个库头文件创建一个只包含声明的文件,没有繁重的代码,如下所示:

Since as a template parameter I only use one or two types anyway I am planning to create, for each library header file, a file that contains only declarations, without the heavy code, like this:

// NEW: fwd-foo.h
template<class T>
class Foo {
  Foo();
  void computeXYZ();
};
template<class T>
void processFoo(const Foo<T>& foo);

然后是一个创建我需要的所有实例的文件.该文件可以单独编译,一劳永逸:

And then one file that creates all the instantiations that I'll need. That file can be compiled separately once and for all:

// NEW: foo.cpp
#include "foo.h"
template class Foo<int>;
template class Foo<double>;
template void processFoo(const Foo<int>& foo);
template void processFoo(const Foo<double>& foo);

现在我可以在我的代码中包含 fwd-foo.h 并且编译时间很短.我将在最后链接 foo.o.

Now I can just include fwd-foo.h in my code and have short compile times. I'll link against foo.o at the end.

当然,缺点是我必须自己创建这些新的 fwd-foo.hfoo.cpp 文件.当然,这是一个维护问题:当发布新的库版本时,我必须使它们适应新版本.还有其他缺点吗?

The downside, of course, is that I have to create these new fwd-foo.h and foo.cpp files myself. And of course it's a maintenance problem: When a new library version is released I have to adapt them to that new version. Are there any other downsides?

我的主要问题是:

我是否有机会从原始foo.h 中自动创建这些新文件,尤其是fwd-foo.h?我必须为许多库头文件(可能是 20 个左右)执行此操作,并且最好使用自动解决方案,尤其是在发布新库版本并且我必须使用新版本再次执行此操作的情况下.是否有任何工具可用于此任务?

Is there any chance I can create these new files, especially fwd-foo.h, automatically from the original foo.h? I have to do this for many library header files (maybe 20 or so), and an automatic solution would be best especially in case a new library version is released and I have to do this again with the new version. Are any tools available for this task?

附加问题:在这种情况下,新支持的 extern 关键字如何帮助我?

Additional question: How can the newly supported extern keyword help me in this case?

推荐答案

我们使用 lzz将单个文件转换为单独的标题和翻译单元.默认情况下,它通常也会将模板定义放入标题中,但是,您可以指定不希望发生这种情况.

We use lzz which splits out a single file into a separate header and translation unit. By default, it would normally put the template definitions into the header too, however, you can specify that you don't want this to happen.

要向您展示如何使用它,请考虑以下事项:

To show you how you might use it consider the following:

// t.cc
#include "b.h"
#include "c.h"

template <typename T> 
class A {
  void foo () {
    C c;
    c.foo ();
    b.foo ();
  }
  B b;
}

将上述文件复制到't.lzz'文件中.根据需要将任何 #include 指令放入单独的 $hdr 和 $src 块中:

Take the above file and copy it to 't.lzz' file. Place any #include directives into separate $hdr and $src blocks as necessary:

// t.lzz
$hdr
#include "b.h"
$end

$src
#include "c.h"
$end

template <typename T> 
class A {
  void foo () {
    C c;
    c.foo ();
    b.foo ();
  }
  B b;
}

现在最后,在文件上运行 lzz,指定它将模板定义放入源文件中.您可以使用源文件中的 $pragma 执行此操作,也可以使用命令行选项-ts":

Now finally, run lzz over the file specifying that it places the template definitions into the source file. You can either do this using a $pragma in the source file, or you can use the command line option "-ts":

这将导致生成以下文件:

This will result in the following files being generated:

// t.h
//

#ifndef LZZ_t_h
#define LZZ_t_h
#include "b.h"
#undef LZZ_INLINE
#ifdef LZZ_ENABLE_INLINE
#define LZZ_INLINE inline
#else
#define LZZ_INLINE       
#endif
template <typename T>
class A
{
  void foo ();
  B b;
};
#undef LZZ_INLINE
#endif

还有:

// t.cpp
//

#include "t.h"
#include "c.h"
#define LZZ_INLINE inline
template <typename T>
void A <T>::foo ()
          {
    C c;
    c.foo ();
    b.foo ();
  }
#undef LZZ_INLINE

然后您可以通过一些 grep/sed 命令运行它们以删除 LZZ 帮助程序宏.

You can then run these through some grep/sed commands to remove the LZZ helper macros.

相关文章