模板列表和用于实例化它们的类型列表的笛卡尔积
Cartesian product of list of templates and list of types to instantiate them with
不确定标题是否具有描述性,但我想要的是:
输入:
- 模板列表(在我的例子中是容器)接受 1 个(必需的,可以是更多可选的)类型参数
- 类型列表
输出:
“笛卡尔积”,其中第一组中的每个模板都用第二组中的每种类型实例化。
示例:
template_list<std::vector, std::set> x type_list<int, double> =>
type_list<std::vector<int>, std::vector<double>, std::set<int>, std::set<double>>
我发现了这个问题,但这是关于两个集合的元素都是类型的情况。
How to create the Cartesian product of a type list?
我想如果没有宏我想要的是不可能的,但我可能遗漏了一些东西。
你可以使用 std::tuple
s. Especially std::tuple_cat
这很好。
示例:
#include <iostream>
#include <set>
#include <tuple>
#include <type_traits>
#include <vector>
template <template <class...> class... C>
struct template_list {};
template <template <class...> class C, class... Ts>
auto toc(const std::tuple<Ts...>&) {
return std::tuple<C<Ts>...>{};
}
template <template <class...> class... C, class... Ts>
auto operator*(template_list<C...>, const std::tuple<Ts...>& tup) {
return std::tuple_cat(toc<C>(tup)...);
}
int main() {
template_list<std::vector, std::set> templ;
std::tuple<int, double, float> typel;
auto res = templ * typel;
static_assert(
std::is_same_v<decltype(res),
std::tuple<std::vector<int>, std::vector<double>,
std::vector<float>, std::set<int>,
std::set<double>, std::set<float>>>);
}
一个类似的解决方案变成了一个更经典的类型特征,其中 res
将导致与上面相同的类型可能如下所示:
template <template <class...> class... C>
struct template_list {};
template <class Temps, class Types>
struct cartesian_product {
template <template <class...> class C, class... Ts>
static std::tuple<C<Ts>...> toc(const std::tuple<Ts...>&);
template <template <class...> class... C, class... Ts>
static auto build(template_list<C...>, const std::tuple<Ts...>& tup)
-> decltype(std::tuple_cat(std::declval<decltype(toc<C>(tup))>()...));
using type = decltype(build(std::declval<Temps>(), std::declval<Types>()));
};
template<class Temps, class Types>
using cartesian_product_t = typename cartesian_product<Temps,Types>::type;
int main() {
using templt = template_list<std::vector, std::set>;
using typelt = std::tuple<int, double, float>;
cartesian_product_t<templt, typelt> res;
}
正如我对他链接问题的回答,Boost.Mp11,这是一个简短的 one-liner(一如既往):
using templates = mp_list<mp_quote<std::vector>, mp_quote<std::set>>;
using types = mp_list<int, double>;
using result = mp_product<
mp_invoke_q,
templates, types>;
static_assert(std::same_as<
result,
mp_list<std::vector<int>,
std::vector<double>,
std::set<int>,
std::set<double>
>>);
Demo.
请注意,您需要 templates
作为 mp_list<mp_quote<C1>, mp_quote<C2>>
而不是 template_list<C1, C2>
,因为如果一切都是类型,元编程会容易得多。但这并不是一个巨大的负担。
不确定标题是否具有描述性,但我想要的是:
输入:
- 模板列表(在我的例子中是容器)接受 1 个(必需的,可以是更多可选的)类型参数
- 类型列表
输出:
“笛卡尔积”,其中第一组中的每个模板都用第二组中的每种类型实例化。
示例:
template_list<std::vector, std::set> x type_list<int, double> =>
type_list<std::vector<int>, std::vector<double>, std::set<int>, std::set<double>>
我发现了这个问题,但这是关于两个集合的元素都是类型的情况。
How to create the Cartesian product of a type list?
我想如果没有宏我想要的是不可能的,但我可能遗漏了一些东西。
你可以使用 std::tuple
s. Especially std::tuple_cat
这很好。
示例:
#include <iostream>
#include <set>
#include <tuple>
#include <type_traits>
#include <vector>
template <template <class...> class... C>
struct template_list {};
template <template <class...> class C, class... Ts>
auto toc(const std::tuple<Ts...>&) {
return std::tuple<C<Ts>...>{};
}
template <template <class...> class... C, class... Ts>
auto operator*(template_list<C...>, const std::tuple<Ts...>& tup) {
return std::tuple_cat(toc<C>(tup)...);
}
int main() {
template_list<std::vector, std::set> templ;
std::tuple<int, double, float> typel;
auto res = templ * typel;
static_assert(
std::is_same_v<decltype(res),
std::tuple<std::vector<int>, std::vector<double>,
std::vector<float>, std::set<int>,
std::set<double>, std::set<float>>>);
}
一个类似的解决方案变成了一个更经典的类型特征,其中 res
将导致与上面相同的类型可能如下所示:
template <template <class...> class... C>
struct template_list {};
template <class Temps, class Types>
struct cartesian_product {
template <template <class...> class C, class... Ts>
static std::tuple<C<Ts>...> toc(const std::tuple<Ts...>&);
template <template <class...> class... C, class... Ts>
static auto build(template_list<C...>, const std::tuple<Ts...>& tup)
-> decltype(std::tuple_cat(std::declval<decltype(toc<C>(tup))>()...));
using type = decltype(build(std::declval<Temps>(), std::declval<Types>()));
};
template<class Temps, class Types>
using cartesian_product_t = typename cartesian_product<Temps,Types>::type;
int main() {
using templt = template_list<std::vector, std::set>;
using typelt = std::tuple<int, double, float>;
cartesian_product_t<templt, typelt> res;
}
正如我对他链接问题的回答,Boost.Mp11,这是一个简短的 one-liner(一如既往):
using templates = mp_list<mp_quote<std::vector>, mp_quote<std::set>>;
using types = mp_list<int, double>;
using result = mp_product<
mp_invoke_q,
templates, types>;
static_assert(std::same_as<
result,
mp_list<std::vector<int>,
std::vector<double>,
std::set<int>,
std::set<double>
>>);
Demo.
请注意,您需要 templates
作为 mp_list<mp_quote<C1>, mp_quote<C2>>
而不是 template_list<C1, C2>
,因为如果一切都是类型,元编程会容易得多。但这并不是一个巨大的负担。