Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use explicit template instantiation for template member functions defined within a class definition?

In an effort to reduce compilation times in a large project that makes liberal use of templates, I've had good results using "extern template" (explicit template instantiation) to prevent common template functions from being defined in many different compilation units.

However, one annoying thing about it is that it doesn't work for member functions defined within the class definition.

For example, I have the following template class:

template <typename T>
struct Foo
{
    static T doubleIt(T input)
    {
        return input * 2;
    }
};

Now, I know that Foo is most commonly used for numeric types, so I add this to the header:

extern template struct Foo<int>;
extern template struct Foo<float>;
extern template struct Foo<double>;

And in a cpp file, add explicit instantiations:

template struct Foo<int>;
template struct Foo<float>;
template struct Foo<double>;

This does not work, as dumpbin.exe on the obj file tells me:

017 00000000 SECT4  notype ()    External     | ?doubleIt@?$Foo@M@@SAMM@Z (public: static float __cdecl Foo<float>::doubleIt(float))

If I change my class definition to define the function outside the class header like so it works correctly:

template <typename T>
struct Foo
{
    static T doubleIt(T input);
};

template <typename T>
T Foo::doubleIt(T input)
{
    return input * 2;
}

Which we can verify using dumpbin:

017 00000000 UNDEF  notype ()    External     | ?doubleIt@?$Foo@M@@SAMM@Z (public: static float __cdecl Foo<float>::doubleIt(float))

The problem with that solution is that it is a lot of typing to move all the function definitions outside of the class definition, especially when you get more template parameters.

I've tried using declspec(__noinline) but it still doesn't extern the functions correctly (and preventing the inlining of the function where possible is undesirable).

One thing that works is to enumerate each function individually, like so, but that of course is even more cumbersome:

extern template int Foo<int>::doubleIt(int);
extern template float Foo<float>::doubleIt(float);
extern template double Foo<double>::doubleIt(double);

What I would like is a way to keep the function definition inside of the class definition, while still allowing the function to be inlined where possible, but when it is not inlined, only creating it in the compilation unit where it is explicitly instantiated (in other words, exactly the same behavior as moving the function outside of the class definition).

like image 869
alvion Avatar asked Mar 01 '18 10:03

alvion


People also ask

How do you instantiate a template in a function?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.

How would you define member function of template class?

Member functions of class templates (C++ only)You may define a template member function outside of its class template definition. The overloaded addition operator has been defined outside of class X . The statement a + 'z' is equivalent to a. operator+('z') .

How do I instantiate a class template in C++?

To instantiate a template class explicitly, follow the template keyword by a declaration (not definition) for the class, with the class identifier followed by the template arguments. template class Array<char>; template class String<19>; When you explicitly instantiate a class, all of its members are also instantiated.

What is the instantiation of the class template?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation.


1 Answers

You can't have it both ways, in order to inline the method the compiler needs to use the source code, as the method is defined inline the compiler doesn't bother compiling it into an object file if it isn't used directly in that object (and even if it is if its inlined in all cases it wont be present in the object as a separate method). The compiler will always have to build your function if its defined in the header, somehow forcing the compiler to store a copy of that function in the object file wont improve performance.

like image 180
Alan Birtles Avatar answered Oct 10 '22 20:10

Alan Birtles