omer
omer

Reputation: 1442

How can i use C++11 explicit templates to reduce binary size?

I am new to the concept of explicit templates, and I'm having troubles in using it and seeing any difference in the binary size. The simple code i wrote goes like this:

comp.cc:

  #include "comp.h"

    using namespace std;

    template <typename T>
    int compare(const T& x, const T& y)
    {
        return x < y ? 0 : 1;
    }


    int func()
    {
        compare(10,9);
        compare(1.5, 7.8);
    }

comp.h:

template <typename T>
int compare(const T& x, const T& y);

main.cc:

#include "comp.h"
#include <iostream>

using namespace std;

extern template int compare(const int&, const int&);
extern template int compare(const double&, const double&);

int main()
{
    compare(10,9);
    cout << compare(1.5, 7.8) << endl;
    return 0;
}

However, not matter if I compile the code with or without the explicit definitions, the size of the binary remains the same. I guess I am missing something simple, but could not find what it was.

Upvotes: 2

Views: 1378

Answers (1)

King Thrushbeard
King Thrushbeard

Reputation: 899

You can actually reduce the code size via explicit template instantiation, however, you need a more complex use case: Given you have a template class as defined in your code of file comp.cc and declared in your file comp.h and you want to use that class with common instatiations (template parameters) in more than one executable, then you can

  1. explicitly instantiate the commonly used templates,
  2. bundle this object code into a shared object (dynamically linked/shared library) and then
  3. use these instantiations from your executables by linking the shared library.

In contrast, if you would use the template instatiations directly in the code of your executables (by including files that also contain the template definitions and not only their declarations), then you would have several (equal) instatiations of your template, one in each executable — yielding a larger object code size in total.

As an example, your explicit template instatiations would go to comp.cc. Note that I renamed the function from compare to less, as just saying 'compare' is not really verbose (how do we compare?) as well as I changed the return value from int to bool:

#include "comp.h"

using namespace std;

template <typename T> bool my_less(const T& x, const T& y)
{
    return x < y;
}

// explicit instatiations
template bool my_less<int>(const int& x, const int& y); // you may omit <int> here
template bool my_less<double>(const double& x, const double& y); // you may omit <double> here

The declaration from comp.h is similar to yours:

template <typename T> bool my_less(const T& x, const T& y);

All this will be compiled and linked using the following Makefile. Note that I use GNU Make on a Linux system, so if you use a differnt system, your approach might differ here:

CXXFLAGS = -O3 -g -Wall -Wextra -std=c++11

LDFLAGS += -L.

comp.o : CXXFLAGS += -fPIC

libmy_comp.so : comp.o
    $(CXX) -shared -o $@ $<

main1 main2 : LDLIBS += -lmy_comp
main1 main2 : libmy_comp.so

In essence, this implements the part described as 'put the template instantiations to the shared library libmy_comp.so and let the executables main1 and main2 resolve undefined references to the template instatiations by linking that library'.

Finally, the main1.cc would do:

#include "comp.h"
#include <iostream>

using namespace std;

int main()
{
    my_less(10,9);
    cout << boolalpha << my_less(1.5, 7.8) << endl;
    return 0;
}

And similarily, main2.cc would be:

#include "comp.h"
#include <iostream>

using namespace std;

int main()
{
    cout << boolalpha << my_less(10,9) << "\n";
    cout << my_less(1.5, 7.8) << endl;
    return 0;
}

Note that in this example, the extern template bool my_less<int>(const int& x, const int& y); is not needed: It can be used to suppress implicit template instatiations, but this is not needed here, since the code of main1.cc and main2.cc only include the declaration but not the definition of the template functions, so the compiler is not able to generate the code anyway.

Upvotes: 3

Related Questions