template<class...Ts>struct types_t {};
template<class...Ts>constexpr types_t<Ts...> types{};
, что позволяет нам работать с пакетами типов без затрат на кортеж.
template<class T>
struct tag_t { using type=T;
template<class...Ts>
constexpr decltype(auto) operator()(Ts&&...ts)const {
return T{}(std::forward<Ts>(ts)...);
}
};
template<class T>
constexpr tag_t<T> tag{};
это позволяет нам работать с типами в качестве значений.
Теперь карта тегов типа - это функция, которая принимает тег типа и возвращает другой тег типа.
template<template<class...>class Z>
struct template_tag_map {
template<class In>
constexpr decltype(auto) operator()(In in_tag)const{
return tag< Z< typename decltype(in_tag)::type > >;
}
};
это берет карту типа шаблона и превращает ее в карту тегов.
template<class R=void, class Test, class Op, class T0 >
R type_switch( Test&&, Op&& op, T0&&t0 ) {
return static_cast<R>(op(std::forward<T0>(t0)));
}
template<class R=void, class Test, class Op, class T0, class...Ts >
auto type_switch( Test&& test, Op&& op, T0&& t0, Ts&&...ts )
{
if (test(t0)) return static_cast<R>(op(std::forward<T0>(t0)));
return type_switch<R>( test, op, std::forward<Ts>(ts)... );
}
, который позволяет нам тестировать условие для группы типов и запускать операцию для той, которая "успешно".
template<class R, class maker_map, class types>
struct named_factory_t;
template<class R, class maker_map, class...Ts>
struct named_factory_t<R, maker_map, types_t<Ts...>>
{
template<class... Args>
auto operator()( std::string_view sv, Args&&... args ) const {
return type_switch<R>(
[&sv](auto tag) { return decltype(tag)::type::name == sv; },
[&](auto tag) { return maker_map{}(tag)(std::forward<Args>(args)...); },
tag<Ts>...
);
}
};
Теперь мы хотим создать общие указатели для некоторого шаблона.
struct shared_ptr_maker {
template<class Tag>
constexpr auto operator()(Tag ttag) {
using T=typename decltype(ttag)::type;
return [](auto&&...args){ return std::make_shared<T>(decltype(args)(args)...); };
}
};
так что общие указатели получают тип.
template<class Second, class First>
struct compose {
template<class...Args>
constexpr decltype(auto) operator()(Args&&...args) const {
return Second{}(First{}( std::forward<Args>(args)... ));
}
};
теперь мы можем составлять функциональные объекты во время компиляции.
Далее подключите.
using Foos = types_t<FooA, FooB, FooC>;
constexpr named_factory_t<std::shared_ptr<Foo>, shared_ptr_maker, Foos> make_foos;
constexpr named_factory_t<std::shared_ptr<BarInterface>, compose< shared_ptr_maker, template_tag_map<Bar> >, Foos> make_bars;
и Готово .
Оригинальный дизайн был на самом деле c ++ 20 с лямбдами вместо этих struct
s для shared_ptr_maker
и т. П.
И make_foos
, и make_bars
имеют нулевое состояние времени выполнения.