[英]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.