Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
518 views
in Technique[技术] by (71.8m points)

c++ - Automatically separate class definitions from declarations?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...