If you can tolerate using an auxiliary function, you can do it as such:
#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}}));
}
Another solution to not have to use an auxiliary function for every parameter could be something like this:
#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}}));
}