是否可以使用基础类型的非默认构造函数,使用相同的参数初始化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
中的所有类型都有一个构造函数,它将Foo
和Bar
作为参数,并且没有默认的构造函数。
答案 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...}...);
}
答案 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) }... };
}