这是对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";
});
}
...但是如何遍历模板列表?
答案 0 :(得分:1)
您可以将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";
});
}
答案 1 :(得分: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其余部分的集成程度如何。