0

I have lots of existing C++ code with template classes that have implementations in the .cpp files. I want to add a template function to one such class. My problem is that I cannot make the compiler instantiate the function template.

I've created a stripped example demonstrating the problem. I want to add the member function convert(), with an own template parameter LenNew:

template <typename Number, int Len>
class MyClass {
public:
    // the function I'm trying to add
    template <int LenNew>
    MyClass<Number, LenNew> convert();

    // other methods I want to keep this way
    void function(); // implemented in .cpp file

private:
    Number n[Len];
};

In the existing setup, the .cpp file implements methods and instantiates the class template:

template <typename Number, int Len>
void MyClass<Number, Len>::function()
{
    // implementation
}

// instantiate template-class with specific template parameters
template class MyClass<double, 1>;

So I added the implementation for my new member function, and tried to instantiate the template, which doesn't seem to work:

template <typename Number, int Len>
template <int LenNew>
MyClass<Number, LenNew> MyClass<Number, Len>::convert()
{
    // implement...
}

// try instantiate
template<> template<> MyClass<double, 2> MyClass<double, 1>::convert<2>();

It compiles fine, but I get an undefined reference when I try to use convert() from a different .cpp file:

main.cpp:(.text+0x1c): undefined reference to `MyClass<double, 2> MyClass<double, 1>::convert<2>()'

Here is a Gist with the demo program: https://gist.github.com/md2k7/8503385

Sorry, there seem to be a lot of very similar questions, but I could still not grasp what is wrong.

cidermole
  • 5,662
  • 1
  • 15
  • 21
  • You cant have the implementation of a template in cpp, it has to be in .h – Borgleader Jan 19 '14 at 11:47
  • Thanks, but I didn't think up the setup with the files; is it impossible to add the template function as I want to? – cidermole Jan 19 '14 at 11:50
  • The template definition must be in the same compilation unit as where it is instantiated. That's why you need to have it in a header file. You can't link against class/function-templates in other compilation units. My suggestion would be to manually fetch the definitions from other cpp files and put them in header-files for reuse. – JorenHeit Jan 19 '14 at 12:01
  • "The template definition must be in the same compilation unit as where it is instantiated.": yes. `myclass.cpp` has the template definition and instantiates the template. – cidermole Jan 19 '14 at 13:15
  • "You can't link against class/function-templates in other compilation units.": The (instantiated) class template stuff (i.e. `MyClass::function()` with ``) is linked correctly with the pre-existing code. Just my new function template `convert()` doesn't link. – cidermole Jan 19 '14 at 13:17
  • 1
    @Borgleader What about [explicit instantiation](http://www.cplusplus.com/articles/1C75fSEw/)? – Constructor Jan 19 '14 at 15:27
  • @Constructor What about it? – Borgleader Jan 19 '14 at 15:30
  • @JorenHeit Linking against templates in other compilation units is possible if explicit instantiation is used. – Constructor Jan 19 '14 at 15:30
  • @Borgleader This mechanism allows to have the implementation of a template in cpp. – Constructor Jan 19 '14 at 15:32
  • It only functions if you know in advance what the parameters will be and export those instantiations. You cannot export a template- only an instantiation of it. – Puppy Jan 19 '14 at 15:45
  • @DeadMG Of course you are right. But this question is about exactly such case as I understood. – Constructor Jan 19 '14 at 15:50
  • Yes, I think so too. I'm just saying that your language is a bit confusing here. The feature is called "extern templates", and you can only export an instantiation, not a template. – Puppy Jan 19 '14 at 16:08
  • @DeadMG I'm sorry for my language. It is extremely bad, I know. It is difficult for me to explain what I really mean. – Constructor Jan 19 '14 at 16:17
  • @DeadMG But extern templates is a slightly different feature, it is useful if class/function template definitions are located in `*.h` file, not `*.cpp`. – Constructor Jan 19 '14 at 16:26
  • @Constructor yes, explicit instantiation is what I meant to use (see Constructor's answer for the correct syntax for that). – cidermole Jan 19 '14 at 16:50

2 Answers2

1

As I understand you want to explicitly instantiate the method of the class template. And this method is also template. You are trying to use such construction for it:

template<> template<> MyClass<double, 2> MyClass<double, 1>::convert<2>();

But this construction means something quite different. It is a declaration of explicitly specialized method template of non-specialized class template. There is right construction in your case:

template MyClass<double, 2> MyClass<double, 1>::convert<2>();

But you also should add an instruction for extra explicit instantiation of MyClass class template:

template class MyClass<double, 2>;

if you really want to use the result of convert method in your code.

Constructor
  • 7,273
  • 2
  • 24
  • 66
0

I've found a workaround - specialize the new member function convert(), explicitly putting the correct version in myclass.cpp:

template <>
template <>
MyClass<double, 2> MyClass<double, 1>::convert()
{
    // implementation...
}

This might lead to some duplicated code for convert(), as it is needed for every version of MyClass<Number, Len> (but for me, currently only 2 versions will need to have this function), but the old code can stay the same.

cidermole
  • 5,662
  • 1
  • 15
  • 21