Внешний шаблонный класс не будет работать - PullRequest
0 голосов
/ 14 мая 2018

Я выделил различные вопросы и комментарии к "внешним" объявлениям шаблонов и тому, как они могут сократить время компиляции, явно указав компилятору не создавать экземпляр определенного класса шаблона или функции в модуле перевода.

Однако я просто не могу заставить эти внешние объявления работать с GCC 8.1.0.

Пример, который я создал, - это в основном принтер кортежей, который std :: cout все элементы кортежа из 512 элементов. Реализация for_each использует общий вызов функции для каждого элемента, в 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>;

Несколько исходных файлов теперь создают экземпляр Test и используют функцию печати. ​​

src0.cpp

#include "test.hpp"

extern template class Test<int>;

void src0() {
  Test<int> t;
  t.print();
}

Насколько я понимаю, Test и его функция печати теперь должны создаваться только один раз test.cpp, а не src0.cpp или другими исходными файлами с объявлением шаблона как extern. Однако это не то, что происходит. Для каждого исходного файла, который я добавляю, который использует Test , выполняется другая реализация ... Так как GCC имеет тенденцию выделять ОЧЕНЬ много памяти для создания вызовов функций и типов / (лямбда-выражения), это становится очень утомительным и отнимает много времени. Ниже приведено изображение потребления памяти моей машиной при компиляции трех исходных файлов с использованием Test ...

memory usage

Я что-то здесь упускаю ?? Я подумал, для чего именно «внешний шаблон» должен использоваться?

реализация for_each для завершения:

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>>>{});
}
...