最初の N
を消費する関数のオーバーライドを提供する必要があります (通常は 1 つの) 引数。
void foo() {
// end condition argument pack is empty
}
template <class First, class... Rest>
void foo(First first, Rest... rest) {
// Do something with first
cout << first << endl;
foo(rest...); // Unpack the arguments for further treatment
}
可変個引数をアンパックすると、次のオーバーロードが検出されます。
例:
foo(42, true, 'a', "hello");
// Calls foo with First = int, and Rest = { bool, char, char* }
// foo(42, Rest = {true, 'a', "hello"}); // not the real syntax
次に、次のレベルで前の Rest
を展開します そして取得:
foo(true, Rest = { 'a', "hello"}); // First = bool
Rest
まで続きます メンバーが含まれていない場合、アンパックすると foo()
が呼び出されます (引数のないオーバーロード)。
種類が異なる場合のパックの保管
引数パック全体を保存したい場合は、 std::tuple
を使用できます
template <class... Pack>
void store_pack(Pack... p) {
std::tuple<Pack...> store( p... );
// do something with store
}
ただし、これはあまり役に立たないようです。
均質な場合のパックの保管
パック内のすべての値が同じ型の場合、次のようにすべて保存できます:
vector<int> reverse(int i) {
vector<int> ret;
ret.push_back(i);
return ret;
}
template <class... R>
vector<int> reverse(int i, R... r) {
vector<int> ret = reverse(r...);
ret.push_back(i);
return ret;
}
int main() {
auto v = reverse(1, 2, 3, 4);
for_each(v.cbegin(), v.cend(),
[](int i ) {
std::cout << i << std::endl;
}
);
}
ただし、これはさらに少ないようです
引数がすべて同じ型の場合、次のように引数を配列に格納できます (配列の最初の引数の型を使用):
template <class T, class ...Args>
void foo(const T& first, const Args&... args)
{
T arr[sizeof...(args) + 1] = { first, args...};
}
int main()
{
foo(1);
foo(1, 10, 100, 1000);
}
型が違うなら boost::any
でいいと思います しかし、指定されたテンプレートの外で、どのアイテムがどのタイプのものか (格納された値をどのように使用するか) をどのように調べるのかわかりません。
編集: 引数がすべて同じ型であり、それらを STL コンテナーに格納する場合は、代わりに std::initializer_list<T>
を使用できます .たとえば、値を逆に格納する Motti の例:
#include <vector>
#include <iostream>
#include <iterator>
template <class Iter>
std::reverse_iterator<Iter> make_reverse_iterator(Iter it)
{
return std::reverse_iterator<Iter>(it);
}
template <class T>
std::vector<T> reverse(std::initializer_list<T> const & init)
{
return std::vector<T>(make_reverse_iterator(init.end()), make_reverse_iterator(init.begin()));
}
int main() {
auto v = reverse({1, 2, 3, 4});
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << std::endl;
}
}
引数の型が異なる場合に配列に固執するには、 std::common_type<>
も使用できます
template<class ...A> void func(A ...args){
typedef typename std::common_type<A...>::type common;
std::array<common, sizeof...(A)> a = {{ args... }};
}
たとえば、func(std::string("Hello"), "folks")
std::string
の配列を作成します .