代码之家  ›  专栏  ›  技术社区  ›  Julius

如何在编译时“迭代”模板列表?

  •  1
  • Julius  · 技术社区  · 6 年前

    这是一个后续问题的摘录 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";
      });
    }
    

    ... 但是如何遍历 ?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Barry    6 年前

    使用 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
  •  1
  •   Julius    6 年前

    您可以包装表单的模板 template<class...> 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>
      >{}
    );
    

    类型

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