Generate an overloaded set of constructors:
#include <tuple>
#include <cstddef>
template <typename T, std::size_t M>
using indexed = T;
template <typename T, std::size_t M, std::size_t... Is>
struct initializer : initializer<T, M, sizeof...(Is) + 1, Is...>
{
using initializer<T, M, sizeof...(Is) + 1, Is...>::initializer;
initializer(indexed<T, Is>... ts)
{
// ts is a pack of std::tuple<int, char, double>
}
};
template <typename T, std::size_t M, std::size_t... Is>
struct initializer<T, M, M, Is...> {};
using foo = initializer<std::tuple<int, char, double>, 20>;
// tuples limit+1 ~~~^
int main()
{
foo({1,'2',3.0});
foo({1,'2',3.0}, {4,'5',6.0});
foo({1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0});
}
DEMO
Generate an overloaded set of function call operators:
#include <tuple>
#include <cstddef>
template <typename T, std::size_t M>
using indexed = T;
template <typename T, std::size_t M, std::size_t... Is>
struct initializer : initializer<T, M, sizeof...(Is) + 1, Is...>
{
using initializer<T, M, sizeof...(Is) + 1, Is...>::operator();
int operator()(indexed<T, Is>... ts) const
{
// ts is a pack of std::tuple<int, char, double>
return 1;
}
};
template <typename T, std::size_t M, std::size_t... Is>
struct initializer<T, M, M, Is...>
{
int operator()() const { return 0; }
};
static constexpr initializer<std::tuple<int, char, double>, 20> foo = {};
// tuples limit+1 ~~~^
int main()
{
foo({1,'2',3.0});
foo({1,'2',3.0}, {4,'5',6.0});
foo({1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0});
}
DEMO 2
Create (or generate with preprocessor macros) a set of overloads that forward arguments to a single implementation:
#include <array>
#include <tuple>
using K = std::tuple<int, char, double>;
void foo(const std::array<K*, 5>& a)
{
// a is an array of at most 5 non-null std::tuple<int, char, double>*
}
void foo(K p0) { foo({&p0}); }
void foo(K p0, K p1) { foo({&p0, &p1}); }
void foo(K p0, K p1, K p2) { foo({&p0, &p1, &p2}); }
void foo(K p0, K p1, K p2, K p3) { foo({&p0, &p1, &p2, &p3}); }
void foo(K p0, K p1, K p2, K p3, K p4) { foo({&p0, &p1, &p2, &p3, &p4}); }
int main()
{
foo({1,'2',3.0});
foo({1,'2',3.0}, {4,'5',6.0});
foo({1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0});
}
DEMO 3
Pass as an array and deduce its size (requires additional pair of parens):
#include <tuple>
#include <cstddef>
template <std::size_t N>
void foo(const std::tuple<int, char, double> (&a)[N])
{
// a is an array of exactly N std::tuple<int, char, double>
}
int main()
{
foo({{1,'2',3.0}, {4,'5',6.0}});
// ^~~~~~ extra parens ~~~~~^
}
DEMO 4
Use an std::initializer_list
as a constructor parameter (to skip extra parens):
#include <tuple>
#include <initializer_list>
struct foo
{
foo(std::initializer_list<std::tuple<int, char, double>> li)
{
// li is an initializer list of std::tuple<int, char, double>
}
};
int main()
{
foo{ {1,'2',3.0}, {4,'5',6.0} };
}
DEMO 5
int
? Probably; you want it to deduce the type from the first argument of the initializer list, right? – Magnetometerint
as any other. 3 looks promising though I don't quite understand it. – Unfortunate{1, '2', 3.0}
can't be deduced asstd::initializer_list
or C-style array; and can't be deduced asstd::tuple<T, char, double>
because{1,
2, 3.0}
itself isn't astd::tuple
. I suppose you have to useK
, or explicit the type callingfoo()
(sofoo<int>( {1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0} );
) or avoid the braces, at least for the first triplet (sofoo(1,'2',3.0, {4,'5',6.0}, {7,'8',9.0})
) to permitT
deduction. – Sunwisefoo(1,'2',3.0, {{4,'5',6.0}, {7,'8',9.0}})
. So the first1
is deduced asint
and the following triplets as astd::tuple<int, char, double>const [2]
– Sunwisefoo<int>(...)
idea would actually need to befoo<int, int, int>(...)
– Toiletfoo<int>()
idea: an additional couple of braces is required. – Sunwisefoo<int>( {1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0} );
) is wrong: also in this case, an additional couple of braces is required (sofoo<int>({{1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0}});
) so you get astd::tuple<T, char, double> const (&arr)[N]
(whereT
is explicated andN
is deduced). – Sunwise