Как «перебрать» список шаблонов во время компиляции? - PullRequest
3 голосов
/ 10 марта 2019

Это извлечение последующего вопроса к этому ответу .

С учетом следующего метода "цикла"

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

... но как перебрать список шаблонов ?

Ответы [ 2 ]

1 голос
/ 10 марта 2019

Использование 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.

1 голос
/ 10 марта 2019

Вы можете обернуть шаблоны формы 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>
  >{}
);

Как только ваши шаблоны будут обернуты в тег 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";
  });
}
...