I suppose that decltype()
, std::declval()
and std::tuple_cat()
can help you a lot.
Given the following couple of overloaded template declared (observe: declared, not defined, following the std::declval()
example) functions to make the cartesian products of type and to collapse (thanks to std::tuple_cat()
) in a single std::tuple
template <template <typename...> class C, typename ... Ts>
constexpr std::tuple<C<Ts...>> tupleExpand (std::tuple<Ts...> const &);
template <template <typename...> class C, typename ... Ts,
template <typename...> class C0, typename ... Ls,
typename ... Cs>
constexpr auto tupleExpand (std::tuple<Ts...> const &, C0<Ls...> const &,
Cs const & ... cs)
-> decltype(std::tuple_cat(
tupleExpand<C>(std::declval<std::tuple<Ts..., Ls>>(), cs...)...));
and the following simple template function (again: only declared) to convert a std::tuple
type with a list of types in a corresponding std::variant
list of types
template <typename ... Ts>
constexpr std::variant<Ts...> tupleToVariant (std::tuple<Ts...> const &);
you can write a MakeVariant
class as follows
template <template <typename...> class C, typename ... Ts>
struct MakeVariant
{
using type = decltype(tupleToVariant(std::declval<
decltype(tupleExpand<C>(std::declval<std::tuple<>>(),
std::declval<Ts>()...))>()));
};
and with a simple using
helper
template <template <typename...> class C, typename ... Ts>
using MakeVariantType = typename MakeVariant<C, Ts...>::type;
you can define your PipelineVariant
type as follows
using PipelineVariant = MakeVariantType<ConfiguredPipeline,
SupportedCriteria,
SupportedStrategies,
SupportedTransformers>;
The following is a full compiling example
#include <tuple>
#include <variant>
template <typename, typename, typename>
struct ConfiguredPipeline
{ };
struct ChiSquared {};
struct Cosine {};
template <typename...>
struct CriteriaList
{ };
using SupportedCriteria = CriteriaList<ChiSquared, Cosine>;
struct Voting {};
template <typename...>
struct StrategiesList
{ };
using SupportedStrategies = StrategiesList<Voting>;
struct AAGrouper11 { };
struct AAGrouper15 { };
template <typename...>
struct TransformerList
{ };
using SupportedTransformers = TransformerList<AAGrouper11, AAGrouper15>;
template <template <typename...> class C, typename ... Ts>
constexpr std::tuple<C<Ts...>> tupleExpand (std::tuple<Ts...> const &);
template <template <typename...> class C, typename ... Ts,
template <typename...> class C0, typename ... Ls,
typename ... Cs>
constexpr auto tupleExpand (std::tuple<Ts...> const &, C0<Ls...> const &,
Cs const & ... cs)
-> decltype(std::tuple_cat(
tupleExpand<C>(std::declval<std::tuple<Ts..., Ls>>(), cs...)...));
template <typename ... Ts>
constexpr std::variant<Ts...> tupleToVariant (std::tuple<Ts...> const &);
template <template <typename...> class C, typename ... Ts>
struct MakeVariant
{
using type = decltype(tupleToVariant(std::declval<
decltype(tupleExpand<C>(std::declval<std::tuple<>>(),
std::declval<Ts>()...))>()));
};
template <template <typename...> class C, typename ... Ts>
using MakeVariantType = typename MakeVariant<C, Ts...>::type;
using PipelineVariant = MakeVariantType<ConfiguredPipeline,
SupportedCriteria,
SupportedStrategies,
SupportedTransformers>;
int main ()
{
static_assert(std::is_same<PipelineVariant,
std::variant<ConfiguredPipeline<ChiSquared, Voting, AAGrouper11>,
ConfiguredPipeline<ChiSquared, Voting, AAGrouper15>,
ConfiguredPipeline<Cosine, Voting, AAGrouper11>,
ConfiguredPipeline<Cosine, Voting, AAGrouper15>>>::value);
}