如何用相同的参数初始化所有元组元素?

时间:2014-03-21 13:26:43

标签: c++ c++11 tuples

是否可以使用基础类型的非默认构造函数,使用相同的参数初始化std::tuple的所有元素?

template <typename... TElements>
struct Container {
    // I'd wish to be able to do something like this:
    Container(Foo foo, Bar bar)
        : tuple(foo, bar)
    {}
    std::tuple<TElements...> tuple;
};

关键是我不知道元组大小(它是由一个可变参数模板化的),所以我不能像我需要的那样多次复制参数。我唯一知道的是TElements中的所有类型都有一个构造函数,它将FooBar作为参数,并且没有默认的构造函数。

3 个答案:

答案 0 :(得分:11)

最明确的方法是在tuple构造函数参数列表中构造每个元素:

template <typename... TElements>
struct Container {
    Container(Foo foo, Bar bar)
        : tuple(TElements{foo, bar}...)
    {}
    std::tuple<TElements...> tuple;
};

这将导致从其对应的构造函数参数移动(或复制)构造元组的每个元素;如果这是不可接受的,你可以使用分段构造:

template <typename... TElements>
struct Container {
    Container(Foo foo, Bar bar)
        : tuple(std::piecewise_construct, (sizeof(TElements), std::tie(foo, bar))...)
    {}
    std::tuple<TElements...> tuple;
};

不幸的是,在这种情况下,我们必须做一些体操(这里是sizeof和一个逗号运算符)来获得提及并忽略的可变列表TElements

答案 1 :(得分:5)

使用双参数包扩展,您可以(尝试)使用给定函数的所有给定参数构造给定元组类的每个元素:

template <class T> struct tuple_construct_t;

template <class... Ts> struct tuple_construct_t<std::tuple<Ts...>> {
  template <class... Args>
  static std::tuple<Ts...> make_tuple(Args&&... args) {
    //this is the central part - the double pack expansion
    return std::make_tuple(Ts{args...}...);
  }
};

// a little free helper function...
template <class Tup, class... Args>
Tup construct_tuple(Args&&... args) {
    return tuple_construct_t<Tup>::make_tuple(std::forward<Args>(args)...);
}

然后在代码的某处:

typedef std::tuple<NoDefault1, NoDefault2> myTuple;
auto t = construct_tuple<myTuple>(Foo{}, Bar{});

完整的工作示例:Link

修改

由于@Rakvan删除了他的答案,我将保留其中的第二个(正确)部分:

template <class ... Ts, class ... Args>
std::tuple<Ts...> cartesian_make_tuple(Args && ... args)
{
    return std::make_tuple(Ts{args...}...);
}

here is a working exaple

答案 2 :(得分:2)

我们想进行可变参数扩展(以获得恰当数量的参数),但我们必须设置一个“提示”来将扩展与我们想要匹配的任何一个包相关联:

template<typename Dummy, typename Value>
Value depends(Value&& value)
{ return std::forward<Value>(value); }

template<typename... Elements>
void example()
{
    // naive attempt to construct all the elements from 0:
    // std::tuple<Elements...> t { 0... };

    // now expansion is tied to the Elements pack
    std::tuple<Elements...> t { depends<Elements>(0)... };

    // with two arguments:
    std::tuple<Elements...> t { { depends<Elements>(0), depends<Elements>(1) }... };
}