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

liz*_*isk 8 c++ tuples c++11

是否可以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;
};
Run Code Online (Sandbox Code Playgroud)

关键是我不知道元组大小(它是由一个可变参数模板化的),因此我无法根据需要多次复制参数.我唯一知道的是,在所有类型TElements有一个构造回吐FooBar作为参数并没有默认构造函数.

eca*_*mur 11

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

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

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

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

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

  • @ 0x499602D2我们需要重复`std :: tie(foo,bar)`多次,因为元组中有元素,所以我们需要扩展`TElements`,但我们实际上并不需要每个元素的类型所以我们必须找到一些方法来忽略它. (3认同)

Arn*_*rtz 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)...);
}
Run Code Online (Sandbox Code Playgroud)

然后在代码中的某个地方:

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

完整的工作示例:链接

编辑:

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

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

这是一个有效的工作