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

发布于 2024-07-15 08:31:44 字数 1416 浏览 11 评论 0原文

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

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

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

因为作为模板参数,我只使用一种或两种类型,所以我计划为每个库头文件创建一个仅包含声明的文件,而不包含大量代码,如下所示

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

:创建我需要的所有实例化的文件。 该文件可以一次性单独编译

// 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

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

我的主要问题是:

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

编辑:

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

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);

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.

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?

And my main question is:

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?

EDIT:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

涫野音 2024-07-22 08:31:44

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

为了向您展示如何使用它,请考虑以下内容:

// 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 块中:

// 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”:

这将生成以下文件:

// 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 辅助宏。

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

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

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

And:

// 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

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

半﹌身腐败 2024-07-22 08:31:44

尝试使用预编译头。 我知道 GCC 和 MSVC 支持此功能。 不过,用法是特定于供应商的。

Try using precompiled headers. I know GCC and MSVC support this feature. Usage is vender-specific, though.

仙气飘飘 2024-07-22 08:31:44

我已经研究同一个问题很长一段时间了。 在您提出的解决方案中,您定义了两次模板类。 如果它定义相同的东西(以相同的顺序)就可以了,但是迟早你肯定会遇到问题。

我的想法是从相反的角度考虑问题。 只要您没有专门化您的实现,它就可以正常工作。

它使用两个宏,这样就不必更新实现文件中的模板参数(但是,如果您想向类添加默认模板参数,请小心)。

// foo.h
#define FOO_TEMPLATE template<typename T>
#define FOO_CLASS Foo<T>

FOO_TEMPLATE
class Foo {
  Foo();
  void computeXYZ();
};

// foo_impl.h
#include "foo.h"
FOO_TEMPLATE
FOO_CLASS::Foo(){}

FOO_TEMPLATE
void FOO_CLASS::computeXYZ() { /* heavy code */ }

通过这样做,您基本上以与非模板类相同的方式工作(当然,您可以使用模板函数执行相同的操作)。

编辑:关于 c++0x 中的 extern 关键字

我相信 c++0x 中的 extern 关键字会有所帮助,但它不会神奇地解决所有问题!

这篇文章

外部模板

每个实例化一个模块
模板本质上创建了一个副本
它在目标代码中。 然后,就起来了
到链接器来处理所有的
最后有多余的目标代码
阶段,从而减缓关键的
编辑-编译-链接周期组成
程序员的一天(或者有时
白日梦)。 将此短路
对象代码垃圾收集,a
编译器供应商数量
已经实现了 extern 关键字
可以放在模板前面。
这是一个标准化的案例
整理现有的行业实践
(双关语)。 在实践中,这是
通过向有关部门发出通知来实施
编译器基本上“不实例化
这里”:

外部模板类 std::vector; 
  

I have been working on the very same issue for quite a while now. In the solution you're proposing, you are defining your template classes twice. It will be ok if it defines the same stuff (in the same order), but you're bound to have problems sooner or later.

What i have come up with is to consider the problem the other way around. As long as you are not specializing your implementation, it works gracefully.

It uses two macros, which avois having to update template arguments in implementation file (be careful, though, if you want to add default template arguments to the class).

// foo.h
#define FOO_TEMPLATE template<typename T>
#define FOO_CLASS Foo<T>

FOO_TEMPLATE
class Foo {
  Foo();
  void computeXYZ();
};

// foo_impl.h
#include "foo.h"
FOO_TEMPLATE
FOO_CLASS::Foo(){}

FOO_TEMPLATE
void FOO_CLASS::computeXYZ() { /* heavy code */ }

By doing this, you essentially work the same way you do with non-template classes (you can do the same thing with template functions, of course).

EDIT : about the extern keyword in c++0x

I believe the extern keyword in c++0x will help, but it won't solve everything magically !

From this article,

Extern Templates

Every module that instantiates a
template essentially creates a copy of
it in the object code. Then, it's up
to the linker to dispose of all of the
redundant object code at the very last
stage, thus slowing the critical
edit-compile-link cycle that makes up
a programmer's day (or sometimes
daydreams). To short-circuit this
object code garbage collection, a
number of compiler vendors have
already implemented an extern keyword
that can go in front of templates.
This is a case of standardization
codifying existing industry practice
(pun intended). In practice, this is
implemented by sending a notice to the
compiler basically to "not instantiate
this here":

extern template class std::vector;
谈下烟灰 2024-07-22 08:31:44

C++0x 将修复外部模板的编译时问题。 不过,我不知道如何自动执行您的要求。

C++0x will fix your compile time issues with extern templates. I don't know an automatic way to do what you ask, though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文