3

I want to create a template class (let's call it Foo) that only accepts a few specific type parameters (let's say only double and float). Normally templates are implemented in the header file (.h) because it is unknown how it will be instantiated in user code. In this case, it makes more sense to implement the class in the implementation file (.cpp) like so:

// Foo.cpp:

template <class T>
class Foo
{
    // Insert members here
};

typedef Foo<double> Foo_d;
typedef Foo<float> Foo_f;

This would instantiate and compile the class when Foo.cpp is compiled. But then how to I declare this in the header file without writing separate declarations for Foo_d and Foo_f?

zdan
  • 28,667
  • 7
  • 60
  • 71
Matt
  • 21,026
  • 18
  • 63
  • 115
  • This doesn't answer your question, but it's bad practice to name a C++ source file with a `.c` extension. –  Jun 12 '12 at 00:30
  • Possibly a duplicate of: http://stackoverflow.com/questions/874298/c-templates-that-accept-only-certain-types This question shows how to only allow certain types to be entered in, so that way you don't have to declare them yourself, it will just throw an error if the user tries something other than what you allow. – tpg2114 Jun 12 '12 at 00:30
  • @Michael That was a silly mistake in the comment. – Matt Jun 12 '12 at 00:31
  • @tpg2114 That is not what I want. I want to compile the instantiations separately from user code. So the user will not be instantiating anything. – Matt Jun 12 '12 at 00:32
  • @Matt You may want to clarify that in the question then, it wasn't clear that was the objective. – tpg2114 Jun 12 '12 at 00:34
  • @Michael That is supposed to be the implementation and instantiation that will be compiled. I am asking what should go in the header. – Matt Jun 12 '12 at 00:37
  • @tpg2114 It seems clear to me if you read the question, can you point out how it is not clear? – Matt Jun 12 '12 at 00:39

2 Answers2

6

You can define the template in your header file, declaring the methods, but without defining them. For example:

template <typename T>
class Foo {
    T val;
public:
    Foo (T t);
    T value ();
};

typedef Foo<double> Foo_d;
typedef Foo<float> Foo_f;

In the .cpp file, you complete the implementations of the methods, and then instantiate the templates that you want.

#include "foo_template.hpp"

template <typename T>
Foo<T>::Foo (T t) : val(t) {}

template <typename T>
T Foo<T>::value () { return val; }

template class Foo<double>;
template class Foo<float>;

The object file should have instantiations for Foo_d and Foo_f from the explicit instantiations of template Foo. Any other type used for template Foo will result in a linking error, since instantiations for them won't exist. Or, more pedantically, the compiler creates instantiations on demand as usual, but it won't be able to resolve the symbols corresponding to the methods of the class, because explicit instantiations for those won't exist.

jxh
  • 69,070
  • 8
  • 110
  • 193
5

Unless I'm mistaken, what you're describing is exactly the use case for the new C++11 extern template feature. To use this feature, you would put the interface for the template class in the header file. You would then end the header file with these lines:

extern template class Foo<float>;
extern template class Foo<double>;

This tells any file that includes the header file not to try to instantiate the template when using it. Then, in your C++ file, you would then implement the template class, and then would end with the lines

template class Foo<float>;
template class Foo<double>;

These last two lines force the compiler to instantiate the template in this translation unit, so you won't get any linker errors.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • Thanks, but is there anyway to do this without `C++11`? – Matt Jun 12 '12 at 00:46
  • 1
    @Matt- This was what the (now deprecated) `export` keyword was supposed to do. This exact problem is one of the reasons that `extern template` was introduced in the first place, and I don't believe that there is a workaround for it. – templatetypedef Jun 12 '12 at 00:48
  • Oh. You should add that to your answer. – Matt Jun 12 '12 at 00:52
  • Mmm I'm trying to make OP's example work using your solution and I can't seem to make it compile. Could you clarify on how to use it? I've read on another thread that this is used when you know that the Foo (for example) template instantiation will be used somewhere else, so you force the compiler to compile it only one time. Am I right? – mfontanini Jun 12 '12 at 00:57
  • @mfontanini- This works just fine with my C++ compiler (g++ 4.6.3). Without seeing how you tried to set this up, I'm not sure how much I can help. – templatetypedef Jun 12 '12 at 01:18