簡體   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