繁体   English   中英

c ++ 17通过生成预先声明的类型列表的笛卡尔积来制作std :: variant

[英]c++17 making std::variant by generating cartesian product of pre-declared lists of types

假设我有一个三个模板类型参数的类。

template<typename Transformer, typename Criteria, typename Strategy>
struct ConfiguredPipeline {};

并在以后的实例化ConfiguredPipeline使用以下类:

template<typename...>
struct CriteriaList
{
};
using SupportedCriteria = CriteriaList<ChiSquared, Cosine>;

template<typename...>
struct StrategiesList
{
};
using SupportedStrategies = StrategiesList<Voting>;

template<typename...>
struct TransformerList
{
};
using SupportedTransformer = TransformerList<AAGrouper11, AAGrouper15>;

我怎样才能生成一个等价于:的std::variant

using PipelineVariant = std::variant< 
ConfiguredPipeline< ChiSquared , Voting , AAGrouper11 > ,
ConfiguredPipeline< ChiSquared , Voting , AAGrouper15 > ,
ConfiguredPipeline< Cosine , Voting , AAGrouper11 > ,
ConfiguredPipeline< Cosine , Voting , AAGrouper15 >>;

通过简单地调用如下函数:

using PipelineVariant = makeVariant< ConfiguredPipeline , SupportedCriteria , SupportedStrategies, SupportedTransformaers >;

我想decltype()std::declval()std::tuple_cat()可以帮到你很多。

给定以下几个重载模板声明(观察:声明,未定义,遵循std::declval()示例)函数,使类型的笛卡尔积和崩溃(感谢std::tuple_cat()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...)...));

和下面的简单模板函数(再次:仅声明)转换std::tuple类型与相应的std::variant类型列表中的类型列表

template <typename ... Ts>
constexpr std::variant<Ts...> tupleToVariant (std::tuple<Ts...> const &);

你可以编写一个MakeVariant类,如下所示

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

并使用简单的using助手

template <template <typename...> class C, typename ... Ts>
using MakeVariantType = typename MakeVariant<C, Ts...>::type;

您可以按如下方式定义PipelineVariant类型

using PipelineVariant = MakeVariantType<ConfiguredPipeline,
                                        SupportedCriteria,
                                        SupportedStrategies,
                                        SupportedTransformers>;

以下是完整的编译示例

#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);
 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM