I've red various questions and comments on "extern" template declarations and how they can reduce compile times by explicitly telling the compiler not to instantiate a certain template class or function within a translation unit.
However I simply can't get those extern declarations to work with GCC 8.1.0.
The example I've created is basically a tuple printer which std::couts all elements of a 512-element tuple. The for_each implementation uses a generic function call on each element, there are multiple versions to be found on SO.
test.hpp
#include <iostream>
#include <tuple>
#include "for_each.hpp"
constexpr auto t = std::tuple{ 0, ..., 511};
template<typename T>
struct Test {
void print() {
for_each(t, [](auto v) { std::cout << v << "\n"; });
}
};
test.cpp
#include "test.hpp"
template class Test<int>;
Multiple source files now create an instance of Test< int > and use the print function.
src0.cpp
#include "test.hpp"
extern template class Test<int>;
void src0() {
Test<int> t;
t.print();
}
To my understanding Test< int > and its print function should now only be created once by test.cpp and not by src0.cpp or other source files with declare the template as extern. However thats not whats happening. For every source file I add which uses Test< int > another instantiation takes place... Since GCC tends to allocate A LOT of memory for the creation of function calls and types/(lambdas) this gets very tedious and time consuming. Below is a picture of the memory consumption of my machine when compiling three source files using Test< int >...
Am I missing something here?? I thought thats exactly whats "extern template" is supposed to be used for?
for_each implementation for completion:
for_each.hpp
#pragma once
#include <tuple>
namespace detail {
template<typename T, typename F, size_t... Is>
constexpr void for_each_impl(T&& t,
F&& f,
std::integer_sequence<size_t, Is...>) {
(f(std::get<Is>(std::forward<T>(t))), ...);
}
} // namespace detail
template<typename T, typename F>
constexpr void for_each(T&& t, F&& f) {
detail::for_each_impl(std::forward<T>(t),
std::forward<F>(f),
std::make_index_sequence<
std::tuple_size_v<std::remove_reference_t<T>>>{});
}