views:

759

answers:

9

I'm compiling a C++ static library and as all the classes are templated, the class definitions and implementations are all in header files. As a result, it seems (under visual studio 2005) that I need to create a .cpp file which includes all the other header files in order for it to compile correctly into the library.

Why is this?

+4  A: 

Even when you will create a .cpp file you still won't receive anything. You need to instantiate templates in order to put them in the library.

Take a look here http://www.parashift.com/c%2B%2B-faq-lite/templates.html#faq-35.13 about how to instantiate templates with concrete types.

Mykola Golubyev
+5  A: 

The compiler doesn't compile header files since these are meant to be included into source files. Prior to any compilation taking place the preprocessor takes all the code from any included header files and places that code into the source files where they're included, at the very location they're included. If the compiler should compile the headerfiles as well, you'd for example have multiple definitions on many things.

Example, this is what the preprocessor sees:

[foo.h]
void foo();

--

[mysource.cpp]
#include "foo.h"

int main()
{
   foo();
}

And this is what the compiler sees:

[mysource.cpp]
void foo();

int main()
{
   foo();
}
sharkin
A: 

Think of Standard Template Library. Your templated classes will be compiled when you utilize them in another project.

orca
A: 

What others have said is true regarding templates not being compiled into the library. However, it is still well worth forcing them to be seen by the compiler (by #including them in a .cpp file) as this way they will at least be checked for syntax.

anon
You're better off writing a set of unit tests than by forcing creation of a static library that doesn't need to exist. After all, many compilers will miss very basic errors on template code if that template code doesn't get called.
Tom
+1  A: 

In c++, templates are just a meta-definition of an actual class. When you compile a templated class, the compiler actually generates the code for the actual class on the fly for the particular type of data passed in (the template is just a "pattern" to copy).

e.g. If you have the following code


struct MyTemplate
{
private:
    float MyValue;

public:
    float Get() { return MyValue; }
    void Set(float value) { MyValue = value; }
};

void main()
{
    MyTemplate v1;
    MyTemplate v2;
    v1.Set(5.0f);
    v2.Set(2);
    v2.Get();
}

What the compiler actually sees is


struct CompilerGeneratedNameFor_MyTemplate_float
{
private:
    float MyValue;

public:
    float Get() { return MyValue; }
    void Set(float value) { MyValue = value; }
};

struct CompilerGeneratedNameFor_MyTemplate_int
{
private:
    int MyValue;

public:
    int Get() { return MyValue; }
    void Set(int value) { MyValue = value; }
};

void main()
{
    CompilerGeneratedNameFor_MyTemplate_float v1;
    CompilerGeneratedNameFor_MyTemplate_int v2;
    v1.Set(5.0f);
    v2.Set(2);
    v2.Get();
}

As you can probably see, the compiler doesn't actually know what code to generate, until you actually declare an instance of your template. This means that the template can't be compiled into a library, because it doesn't know what the template will actually end up being. The good news about this is that you don't actually need ANY library to be compiled or included if you just distribute the header files that include the template definition.

Also, as a side note, the '#include' pre-compiler command actually just tells the pre-compiler to replace the '#include' with everything from that file.

Grant Peters
+1  A: 

You're trying to create something unnecessary. Most C libraries (and all C++ libraries) get distributed as two portions:

  • Interface (foo.h)
  • Implementation (foo.lib)

For C++ template code, all of your library must be compiled by your end-users, because that's how templates work. There's no reason to provide a pre-compiled library. In this case, your can think of your library distribution as this:

  • Interface (foo.h)
  • Implementation (foo-inl.h)

As Niel said above, it's useful to have implementations just for your own testing purposes, and it's probably worthwhile distributing those with the library itself. So you should have a separate suite of unit tests that exercise your code; but those tests shouldn't be part of the library itself.

Tom
A: 

You don't need to generate a .lib if all you classes are templates, take a look a boost or the stlport they don't have a .lib that they distribute [1].

Templates are compiled when they are used.

[1] Strictly speaking they distribute libraries for the more advanced features like regular expressions, iostream etc., but auxiliary libraries are used by others templates, the templates by themselves are not distributed in library form.

Ismael
+2  A: 

If all your code is in .h files, then you don't need to compile a static library to use the code.

All the code is available to the library's use at the compilation time, so nothing is needed at link time.

Arkadiy
A: 

If your library is all implemented in header files, you don't need to build any binary to use it. That said. I usually create a .cpp file during my initial development phase of header only library. Why? Compilers don't try to compile or even parse your template until it is actually being used. Having a .cpp file and have some dummy code there to instantiate the templates help me find syntax errors earlier during development. So i can add some template code, hit compile, fix syntax error, add more code, compile...etc. If you every try to hunt down some silly syntax error after adding hundreds of lines of code, you'll know what i mean. Once my library is ready for unit test, i'll remove the .cpp file and rely on unit testes to drive my development.

Also, if your only compile your code using VC++, one thing you need to be aware of is that VC++ doesn't try to compile all template member functions until it is actually used. For example:

template <typename T>
class MyTemplate
{
public:
    MyTemplate() {} // default constructor

    MyTemplate(int) { 
        1 = 2
        // other syntax error code here
    }
};

void f() { MyTemplate<int> myt(); } // compile fine in VC
void g() { MyTemplate<int> myt(1); } // syntax error

The f() will compile just fine with VC++ 2003, g++ will catch the syntax error. I think VC8 and VC9 also have the same problem.

Shing Yip