Info
-
Did you about typename erasure technique to reduce compilation times with templates?
Example
template<auto...> struct long_type {};
using long_type_t = decltype(
[]<auto... Ns>(std::index_sequence<Ns...>) {
return long_type<Ns...>{};
}
(std::make_index_sequence<42>{})
);
// typename erasure
struct short_type_t : long_type_t{};
// generic typename erasure
template<class T> using typename_erasure = decltype([] {
struct s : T { using T::T; }; // generated in the compiler as `$0::s` or similar
return s{};
}());
int main() {
assert(std::string_view{typeid(long_type_t).name()}.size() > 100); // long...
assert(std::string_view{typeid(short_type_t).name()}.size() < 15); // short
assert(std::string_view{typeid(typename_erasure<long_type_t>).name()}.size() < 25); // short
}
Puzzle
- Can you implement typename_erasure function which will erase all given types?
template<class... Ts>
[[nodiscard]] constexpr auto typename_erasure; // TODO
template<auto... Ns> struct long_type{ };
template<auto N> using long_type_t = decltype(
[]<auto... Ns>(std::index_sequence<Ns...>) {
return long_type<Ns...>{};
}
(std::make_index_sequence<N>{})
);
#include <string_view>
#include <typeinfo>
[[nodiscard]] consteval auto type_name(auto) { return std::string_view{__PRETTY_FUNCTION__}; }
static_assert(std::size(type_name(typename_erasure<long_type_t<100>, long_type_t<200>>())) < 42);
static_assert(not std::is_base_of_v<long_type_t<300>, decltype(typename_erasure<long_type_t<100>, long_type_t<200>>())>);
static_assert(std::is_base_of_v<long_type_t<100>, decltype(typename_erasure<long_type_t<100>, long_type_t<200>>())>);
static_assert(std::is_base_of_v<long_type_t<200>, decltype(typename_erasure<long_type_t<100>, long_type_t<200>>())>);
Solutions
template<class... Ts>
[[nodiscard]] constexpr auto typename_erasure()
{
struct s : Ts... {
s() = default;
s(Ts &&...arg) : Ts(::std::forward<Ts>(arg)) ... {}
};
return s{};
}
template<class... Ts>
[[nodiscard]] constexpr auto typename_erasure(){
struct s : public Ts...{};
return s{};
};
template<class T> using typename_erasure_one = decltype([] {
struct s : T { using T::T; };
return s{};
}());
template<class... Ts>
[[nodiscard]] constexpr auto typename_erasure = [] {
struct a : typename_erasure_one<Ts>...{};
return a{};
};