递归可变参数函数模板

时间:2015-03-05 14:48:31

标签: c++ c++11 variadic-templates

我想编写一个类方法,它接受一个模板参数包,但是零参数,并对类型进行“迭代”:

struct Bar {
    template <typename T, typename... Ts>
    void foo() {
        // something with T that involves Bar's members
        foo<Ts...>();
    }
};

实现此目的的首选方法是什么?

3 个答案:

答案 0 :(得分:3)

您可以使用以下内容:

struct Bar {
    template <typename... Ts>
    void foo() {
        int dummy[] = {0 /*Manage case where Ts is empty*/,
                       (bar<Ts>(), void() /* To avoid overload `operator,` */, 0)...};
        (void) dummy; // suppress warning for unused variable.
    }

    template <typename T>
    void bar()
    {
        // something with T that involves Bar's members
    }

};

在C ++ 17中,可以使用折叠表达式简化它:

struct Bar {
    template <typename... Ts>
    void foo() {
        (static_cast<void>(bar<Ts>()), ...);
    }

    template <typename T>
    void bar()
    {
        // something with T that involves Bar's members
    }

};

答案 1 :(得分:3)

template<class...Fs>
void do_in_order(Fs&&...fs) {
  int _[]={0, ( std::forward<Fs>(fs)(), void(), 0 )...};
  (void)_;
}

隐藏以从左到右的顺序执行一组函数对象所需的语法。

然后:

struct Bar {
  template <class... Ts>
  void foo() {
    do_in_order([&]{
      using T = Ts;
      // code 
    }...);
  }
};

在符合标准的编译器中,我们将运行// code,其中T是从左到右的每种类型。

请注意,一些声称是C ++ 11编译器的编译器可能无法编译上述内容。

这种技术的优点在于它隐藏了令人讨厌的&#34;扩展和评估模板&#34;具有明确名称的函数中的代码。你只需编写do_in_order一次,通常几乎每次使用该数组扩展技巧都足够了。

使用这种深奥的语法有两个重要原因而不是&#34;更简单&#34;递归解决方案。

首先,它使优化器更容易。优化器有时会在一堆递归调用后放弃。

其次,传统递归函数的函数签名的长度名称之和在O(n ^ 2)处增长。如果使用帮助程序类型,则名称的总长度也为O(n ^ 2)。除非您小心,否则会导致编译时间,链接时间和二进制大小膨胀。

在C ++ 1z中,有一些&#34; fold&#34;语法可能使上面的深奥部分不那么深奥。

答案 2 :(得分:0)

我喜欢重载函数和使用类型列表:

#include <iostream>
#include <typeinfo>

template <typename ...Ts> struct typelist { };

void foo_impl(typelist<> )
{
  // we are finished
}

template <typename T, typename ...Ts>
void foo_impl(typelist<T, Ts...> )
{
  std::cout << typeid(T).name() << ", ";
  foo_impl(typelist<Ts...>{});
}



template <typename ...Ts>
void foo()
{
  std::cout << "called with <";
  foo_impl(typelist<Ts...>{});
  std::cout << ">" << std::endl;
}


int main()
{
  foo<int, char, float>();
}