1

Assume you use the same template_function<T>() in two other .cpp files (a_uses_template.cpp and b_uses_template.cpp), which both instanciate the template implicitly.

As I understand it, this should cause code duplication, because a_uses_template.cpp and b_uses_template.cpp are compiled separately, so template_function<T>() gets instanciated twice.
However, if I change the code to use just one explicit instanciation, then the resulting executable file is even bigger, not smaller as expected.

How is this possible?

main.cpp

#include <iostream>
#include "a_uses_template.h"
#include "b_uses_template.h"

int main() {
    function_a_uses_template();
    function_b_uses_template();
}

a_uses_template.h

#ifndef A_USES_TEMPLATE_H_
#define A_USES_TEMPLATE_H_

void function_a_uses_template();

#endif /* A_USES_TEMPLATE_H_ */

a_uses_template.cpp

#include <iostream>
#include "template_function.h"
#include "a_uses_template.h"

void function_a_uses_template() {
    std::cout << "function_a_uses_template, template_function<int>(): "
            << template_function<int>() << std::endl;
}

The following are the two variants of template_function.h /.cpp, first the one with is used together with two implicit instanciations and then the two files which contain one explicit instanciation.

template_function.h (Variant with two implicit instanciations)

#ifndef TEMPLATE_FUNCTION_H_
#define TEMPLATE_FUNCTION_H_

#include <cstddef>

template<typename T> size_t template_function() {
    size_t s = sizeof(T);

    // some code that the compiler won't erase during optimization
    while (s != 1) {
        if ((s & 1) == 0) {
            s /= 2;
        } else {
            s = 3 * s + 1;
        }
    }

    return s;
}

#endif /* TEMPLATE_FUNCTION_H_ */

template_function.h (Variant with one explicit instanciation)

#ifndef TEMPLATE_FUNCTION_H_
#define TEMPLATE_FUNCTION_H_

#include <cstddef>

template<typename T> size_t template_function();

#endif /* TEMPLATE_FUNCTION_H_ */

template_function.cpp (Variant with one explicit instanciation)

#include "template_function.h"

template<typename T> size_t template_function() {
    size_t s = sizeof(T);

    // some code that the compiler won't erase during optimization
    while (s != 1) {
        if ((s & 1) == 0) {
            s /= 2;
        } else {
            s = 3 * s + 1;
        }
    }

    return s;
}

template size_t template_function<int>(); // one explicit instanciation
Daniel S.
  • 6,458
  • 4
  • 35
  • 78
  • 1
    Generally speaking the linker will eliminate any duplicate template instantiations. – john Aug 11 '20 at 11:12
  • 1
    From standard, to not have UB, your loop ends with `s == 1`.... so compiler might optimize to `return 1;`. – Jarod42 Aug 11 '20 at 11:37
  • See for example [C Compilers Disprove Fermat’s Last Theorem](https://blog.regehr.org/archives/140). – Jarod42 Aug 11 '20 at 11:48
  • 1
    and also '"C Compilers Disprove Fermat’s Last Theorem" with [code](https://godbolt.org/z/3skK9j). – Jarod42 Aug 11 '20 at 11:54
  • Thanks for the valuable comments, particularly for pointing out the older question of which mine is a duplicate. I found the answers to my question there. – Daniel S. Aug 11 '20 at 12:12
  • @Jarod42 cool code example! I was always a bit unsure if my trick really works. I used this in Java a lot where it worked. – Daniel S. Aug 11 '20 at 12:15

0 Answers0