迭代C ++可变参数模板

时间:2017-04-04 10:57:13

标签: c++ templates variadic

我有以下内容:

template<typename FIRST, typename SECOND>
Sender *createSenderChain() {
    return new FIRST(new SECOND());
}

是否可以使模板变量:

template<typename FIRST, typename ...Args>
Sender *createSenderChain() {
    return new FIRST(new SECOND(new THIRD(new ...))  <-- This is the pattern I want, 
                                                         but how should it be done 
                                                         using the args list?
}

3 个答案:

答案 0 :(得分:8)

您可以使用递归

根据您对Sender

的定义进行猜测
struct Sender { ~Sender() {} };

struct A : Sender { A(Sender* = nullptr) {} };
struct B : Sender { B(Sender* = nullptr) {} };
struct C : Sender { C(Sender* = nullptr) {} };


// Base case
template <typename T>
Sender* createSenderChain()
{
    return new T();
}

// Recursive case
template <typename T1, typename T2, typename ...Ts>
Sender* createSenderChain()
{
    return new T1(createSenderChain<T2, Ts...>());
}

int main()
{
    auto ptr = createSenderChain<A, B, C>();
}

live demo

答案 1 :(得分:4)

您可以使用不同的模板参数调用相同的可变参数模板函数:

template<typename FIRST, typename SECOND, typename ...Args>
Sender* createSenderChain() {
    return new typename FIRST(createSenderChain<SECOND, Args...>());
}

template<typename FIRST>
Sender* createSenderChain() {
    return new typename FIRST();
}

在第一个函数中,我们不仅明确声明typename FIRST,还明确指出typename SECOND以避免将此实现与createSenderChain<T>调用匹配,因为可变参数部分可能与空列表类型匹配

答案 2 :(得分:2)

由于您的问题没有指定使用哪种C ++变体,因此该解决方案使用C ++ 17。这意味着它可以避免递归。

我们通过二进制折叠来解决函数的组合。为此,我们首先需要将函数对象转换为可以通过二进制操作组成的对象:

template<class F>
struct compose_t {
  F f;
  template<class Lhs, class Rhs>
  auto operator*( compose_t<Lhs> lhs, compose_t<Rhs> rhs ) {
    auto r =
      [lhs = std::move(lhs).f, rhs = std::move(rhs).f](auto&&...args)
      ->decltype(auto)
      { return lhs(rhs(decltype(args)(args)...)); }
    return compose_t<decltype(r)>{ std::move(r) };
  }
  template<class...Args>
  decltype(auto) operator()(Args&&...args){
    return f(std::forward<Args>(args)...);
  }
};
template<class F>
compose_t<F> compose(F f) { return {std::forward<F>(f)}; }

这将创建一个可组合的函数对象,该对象由*组成。

接下来,我们需要一个表示“在堆上构造一个T”的对象,而不指定对象完成的

template<class T>
auto maker() {
  return [](auto&&...args) {
    return std::make_unique<T>( decltype(args)(args)...) )
  };
}

maker返回一个函数对象,该函数对象表示稍后要提供的一组参数上的callilng make_unique<T>。我可以用原始指针做到这一点,但我拒绝。

template<typename ...Args>
std::unique_ptr<Sender> createSenderChain() {
  return (compose( maker<Args>() ) * ...)();
}

并完成了。请注意,我使用unique_ptr<Sender>而不是Sender*,因为我拒绝提供您不应使用的垃圾代码。