[英]How to write function for generic nested container in c++17?
我想实现一个 function ,其参数类型为List<List<int>>
其中List
可能是std::vector
或std::list
,甚至是带有自定义分配器的std::vector
,同时,它也接受原始大括号括起来的表达式
目前我有一个本地尝试如下
#include <iostream>
#include <list>
#include <vector>
template<typename LLO = std::vector<std::vector<int>>>
void f(const LLO& a) {
for (const auto& i : a) {
for (const auto& j : i) {
std::cout << j;
}
std::cout << '\n';
}
}
template<typename LO = std::vector<int>, int = 0>
void f(const std::initializer_list<LO>& a) {
f(std::vector(a));
}
int main() {
f({{1, 2}, {3, 4}});
f({std::vector{1, 2}, {3, 4}});
f(std::list{std::list{1, 2}, {3, 4}});
f({std::list{1, 2}, {3, 4}});
}
最重要的测试是f({std::list{1, 2}, {3, 4}})
,它要求我显式地为 std::initializer_list 编写一个丑陋的重载。
事实上,在我的情况下,我有三个像这样的嵌套容器类型的 arguments,如果我使用这个解决方案,我必须编写2^3=8
重载函数
我想知道是否有一些好看的解决方案,我的代码在c++17下,如果可以在c++20中用概念轻松实现,这次对我没有帮助,但我还是很好奇。
如果您可以容忍使用辅助 function,您可以这样做:
#include <iostream>
#include <list>
#include <vector>
template<class LLO>
LLO
make_param(LLO&& a) { return std::forward<LLO>(a); }
template<template<class...> class Cont = std::vector, class T = int, class... Rest>
auto
make_param(std::initializer_list<Cont<T, Rest...>> ilist)
{
return Cont<Cont<T, Rest...>, Rest...>(ilist);
}
template<class LLO>
void f(const LLO& p)
{
//code here
}
template<class LLO1, class LLO2>
void f(const LLO1& p1, const LLO2& p2)
{
//more code here
}
int main()
{
f(make_param({{1, 2}, {3, 4}}));
f(make_param({std::vector{1, 2}, {3, 4}}));
f(make_param(std::list{std::list{1, 2}, {3, 4}}));
f(make_param({std::list{1, 2}, {3, 4}}));
std::vector<int, std::allocator<float>> v;
f(make_param({v, v}));
f(make_param({{1, 2}, {3, 4}}), make_param({std::list{1, 2}, {3, 4}}));
}
不必为每个参数使用辅助 function 的另一种解决方案可能是这样的:
#include <iostream>
#include <list>
#include <vector>
#include <tuple>
template<class Item, template<class...> class Tuple, class... Types, std::size_t... Is>
std::tuple<Types..., Item>
tuple_append_impl(Item&& item, Tuple<Types...>& t, std::index_sequence<Is...>)
{
return { std::move(std::get<Is>(t))..., std::forward<Item>(item) };
}
template<class Item, class... Types>
std::tuple<Types..., Item>
tuple_append(Item&& item, std::tuple<Types...>& t)
{
return tuple_append_impl(std::forward<Item>(item), t, std::make_index_sequence<sizeof...(Types)>());
}
template<class... Conts>
struct param
{
template<class LLO>
param<Conts..., LLO>
operator()(LLO&& a)
{
return { tuple_append(std::forward<LLO>(a), conts) };
}
template<template<class...> class Cont = std::vector, class T = int, class... Rest>
param<Conts..., Cont<Cont<T, Rest...>, Rest...>>
operator()(std::initializer_list<Cont<T, Rest...>> ilist)
{
return { tuple_append(Cont<Cont<T, Rest...>, Rest...>(ilist), conts) };
}
std::tuple<Conts...> conts;
};
template<>
struct param<>
{
template<class LLO>
param<LLO>
operator()(LLO&& a) { return {std::forward<LLO>(a)}; }
template<template<class...> class Cont = std::vector, class T = int, class... Rest>
param<Cont<Cont<T, Rest...>, Rest...>>
operator()(std::initializer_list<Cont<T, Rest...>> ilist)
{
return {Cont<Cont<T, Rest...>, Rest...>(ilist)};
}
};
param() -> param<>;
template<class Cont>
void f(const param<Cont>& p)
{
//function taking one param
auto& llo = std::get<0>(p.conts);
}
template<class Cont1, class Cont2>
void f(const param<Cont1, Cont2>& p)
{
//function taking two param
auto&& llo0 = std::get<0>(p.conts);
auto&& llo1 = std::get<1>(p.conts);
}
template<class Cont1, class Cont2, class Cont3>
void f(const param<Cont1, Cont2, Cont3>& p)
{
//function taking three param
}
template<class... Conts>
void f2(const param<Conts...>& p)
{
//function taking arbitrary amount of params
}
int main()
{
f(param<>()({{1, 2}, {3, 4}}));
f(param<>()({std::vector{1, 2}, {3, 4}}));
f(param<>()(std::list{std::list{1, 2}, {3, 4}}));
f(param<>()({std::list{1, 2}, {3, 4}}));
f(param<>()({{1, 2}, {3, 4}})
({std::list{1, 2}, {3, 4}})
(std::list{std::list{1, 2}, {3, 4}}));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.