【问题标题】:How to "iterate" over a list of templates at compile time?如何在编译时“迭代”模板列表?
【发布时间】:2019-03-10 17:41:45
【问题描述】:

这是对this answer的后续问题的提取。

鉴于以下“循环”技术

#pragma once
// loop.hpp

#include <type_traits>
#include <utility>

template<std::size_t... indices, class LoopBody>
void loop_impl(std::index_sequence<indices...>, LoopBody&& loop_body) {
  (// C++17's fold expression
    loop_body(std::integral_constant<std::size_t, indices>{}),
    ...
  );
}

template<std::size_t N, class LoopBody>
void loop(std::integral_constant<std::size_t, N>, LoopBody&& loop_body) {
  loop_impl(std::make_index_sequence<N>{}, std::forward<LoopBody>(loop_body));
}

可以像这样遍历类型列表:

#include <iostream>
#include <string_view>
#include <tuple>

#include "loop.hpp"

template<class T>
std::string_view inspect() {
  return __PRETTY_FUNCTION__;
}

using Types = std::tuple<int, int, char, bool, double>;

int main() {
  loop(std::tuple_size<Types>{}, [&] (auto i) {
    using T = std::tuple_element_t<i, Types>;

    std::cout << i << ": " << inspect<T>() << "\n";
  });
}

...但是如何遍历 模板列表

【问题讨论】:

    标签: c++ templates c++17 variadic-templates template-meta-programming


    【解决方案1】:

    使用Boost.Mp11,第一个版本是:

    static constexpr auto size = std::tuple_size_v<Types>;
    mp_for_each<mp_iota_c<size>>([&] (auto i) {
        /* ... */
    });
    

    对模板执行此操作的方式基本相同:

    using list = mp_list<mp_quote<std::tuple>, mp_quote<std::pair>>;
    mp_for_each<list>([&](auto f){
       // v is a tuple<int, char> the first time around and a pair<int, char>
       // the second time around
       mp_invoke_q<decltype(f), int, char> v;
    });
    

    当然,你可以在正文中使用f 做任何你想做的事情,我只是将它作为mp_quote 的示例调用,以及它与Mp11 的其余部分的集成程度。

    【讨论】:

      【解决方案2】:

      您可以将template&lt;class...&gt; class 形式的模板包装成如下标签类型:

      #pragma once
      // template_tag.hpp
      
      #include <tuple>
      #include <type_traits>
      
      template<
        template<class...>
        class Tmpl_
      >
      struct TemplateTag {
        template<class... Ts>
        using insert = Tmpl_<Ts...>;
      
        template<
          template<template<class... > class>
          class TmplTmpl
        >
        using rewrap_into = TmplTmpl<Tmpl_>;
      };
      
      // convenience helper
      template<class TmplTag, class... Ts>
      using InsertTemplateArgs = typename TmplTag::template insert<Ts...>;
      
      static_assert(
        std::is_same<
          InsertTemplateArgs< TemplateTag<std::tuple>, int, bool >,
          std::tuple<int, bool>
        >{}
      );
      
      // convenience helper
      template<class TmplTag, template<template<class...> class> class TmplTmpl>
      using RewrapTemplateInto = typename TmplTag::template rewrap_into<TmplTmpl>;
      
      template<template<class...> class Tmpl>
      struct OtherTemplateTag {};
      
      static_assert(
        std::is_same<
          RewrapTemplateInto< TemplateTag<std::tuple>, OtherTemplateTag >,
          OtherTemplateTag<std::tuple>
        >{}
      );
      

      一旦您的模板被包装到标签 type 中,您就可以像以前一样迭代类型:

      #include <iostream>
      #include <string_view>
      #include <tuple>
      #include <utility>
      #include <variant>
      
      #include "loop.hpp"
      #include "template_tag.hpp"
      
      template<class T>
      std::string_view inspect() {
        return __PRETTY_FUNCTION__;
      }
      
      using Templates = std::tuple<
        TemplateTag<std::tuple>,
        TemplateTag<std::tuple>,
        TemplateTag<std::pair>,
        TemplateTag<std::variant>
      >;
      
      template<
        template<class...>
        class Tmpl
      >
      struct AnotherTemplateTag {};
      
      int main() {
        loop(std::tuple_size<Templates>{}, [&] (auto i) {
          using TmplTag = std::tuple_element_t<i, Templates>;
      
          std::cout << i << ": " << inspect<TmplTag>() << "\n";
      
          using AnotherTmplTag = RewrapTemplateInto<TmplTag, AnotherTemplateTag>;
          std::cout << "   " << inspect<AnotherTmplTag>() << "\n";
      
          using TmplWithArgs = InsertTemplateArgs<TmplTag, int, long>;
          std::cout << "   " << inspect<TmplWithArgs>() << "\n";
        });
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-20
        • 2020-08-01
        • 1970-01-01
        相关资源
        最近更新 更多