从variadic模板中读取参数

时间:2010-09-06 12:37:19

标签: c++ c++11

我对如何通过使用可变参数模板从元组中读取每个参数感到有点困惑。

考虑这个功能:

template<class...A> int func(A...args){
int size = sizeof...(A);
.... }

我从主文件中调用它,如:

func(1,10,100,1000);

现在,我不知道如何扩展func的主体以便能够分别读取每个参数,以便我可以将参数存储在数组中。

4 个答案:

答案 0 :(得分:12)

您必须为使用第一个N(通常是一个)参数的函数提供覆盖。

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; 
        }
    );
}

然而,这似乎甚至更少有用。

答案 1 :(得分:3)

如果参数都是相同的类型,你可以将参数存储在这样的数组中(使用数组的第一个参数的类型):

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;
    }
} 

答案 2 :(得分:2)

如果参数有不同的类型,为了坚持数组,你也可以使用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的数组。

答案 3 :(得分:1)

如果需要在数组中存储参数,可以使用boost::any数组,如下所示:

template<typename... A> int func(const A&... args)
{
  boost::any arr[sizeof...(A)] = { args... };
  return 0;
}