如何将元组的值转发给成员初始值设定项?
How do I forward the values of tuple to a member initializer?
我需要将元组的值转发给成员初始值设定项:
struct Struct {
Member1 member1;
Member2 member2;
template<typename Tuple1, typename Tuple2>
Struct( Tuple1&& tuple1, Tuple2&& tuple2 )
: member1(tuple1...), member2(tuple2...)
{}
};
上面的代码显然是无效的。怎么表达呢?
Member1
和 Member2
没有 default/copy/move 构造函数。
我知道 std::apply
,如 How do I expand a tuple into variadic template function's arguments? 中所述。我也知道 std::make_from_tuple
。但是我不知道如何在成员初始值设定项中使用这些中的任何一个。
任何 C++ 标准都可以(最好是 C++17,但 C++20 也可以)。
澄清一下,我的真正目标是创建一个 Struct
,将两组可变参数传递给它以完美转发它们以初始化 member1
和 member2
。我认为将两个集合“分组”成元组可能是个好主意,因为那是 std::map::emplace
所做的。其他方法也可以工作(例如,在两组可变参数之间传递一个特殊对象)。
cppreference.com has a nice example of a sample implementation of std::make_from_tuple
,但是,正如您所发现的,由于缺少底层 class.[=14= 的复制构造函数,您无法使用它]
但是,它的面包屑导航可让您对其进行调整以解决这些限制:
#include <tuple>
#include <iostream>
struct Member1 {
Member1(int a, int b)
{
std::cout << a << " "
<< b
<< std::endl;
}
Member1(const Member1 &)=delete;
Member1(Member1 &&)=delete;
};
struct Member2 {
Member2(const char *str)
{
std::cout << str << std::endl;
}
Member2(const Member2 &)=delete;
Member2(Member2 &&)=delete;
};
// De-obfucation shortcut
template<typename Tuple>
using make_index_sequence_helper=std::make_index_sequence
<std::tuple_size_v<std::remove_reference_t<Tuple>>>;
struct Struct {
Member1 member1;
Member2 member2;
template<typename Tuple1, typename Tuple2>
Struct( Tuple1&& tuple1,
Tuple2&& tuple2 )
: Struct{std::forward<Tuple1>(tuple1),
make_index_sequence_helper<Tuple1>{},
std::forward<Tuple2>(tuple2),
make_index_sequence_helper<Tuple2>{}}
{
}
template<typename Tuple1, std::size_t ...tuple1_args,
typename Tuple2, std::size_t ...tuple2_args>
Struct(Tuple1 && tuple1,
std::index_sequence<tuple1_args...>,
Tuple2 && tuple2,
std::index_sequence<tuple2_args...>)
: member1{std::get<tuple1_args>(tuple1)...},
member2{std::get<tuple2_args>(tuple2)...}
{
}
};
int main()
{
Struct s{ std::tuple<int, int>{2, 3},
std::tuple<const char *>{"Hello world"}};
return 0;
}
使用 gcc 10 和 -std=c++17
进行测试。
std::make_from_tuple
确实是正确的选择:
#include <tuple>
struct Member1 {
Member1(int x,float y, char z){}
Member1(const Member1& other)=delete;
Member1(Member1&& other)=delete;
};
struct Member2 {
Member2(int x,float y, char z){}
Member2(const Member2& other)=delete;
Member2(Member2&& other)=delete;
};
struct Struct {
Member1 member1;
Member2 member2;
template<typename Tuple1, typename Tuple2>
Struct(Tuple1&& tuple1, Tuple2&& tuple2)
: member1(std::make_from_tuple<Member1>(std::forward<Tuple1>(tuple1))),
member2(std::make_from_tuple<Member2>(std::forward<Tuple2>(tuple2)))
{}
};
int main(){
Struct c(std::tuple{1,1.1,'c'},std::tuple{2,2.2,'x'});
}
我需要将元组的值转发给成员初始值设定项:
struct Struct {
Member1 member1;
Member2 member2;
template<typename Tuple1, typename Tuple2>
Struct( Tuple1&& tuple1, Tuple2&& tuple2 )
: member1(tuple1...), member2(tuple2...)
{}
};
上面的代码显然是无效的。怎么表达呢?
Member1
和 Member2
没有 default/copy/move 构造函数。
我知道 std::apply
,如 How do I expand a tuple into variadic template function's arguments? 中所述。我也知道 std::make_from_tuple
。但是我不知道如何在成员初始值设定项中使用这些中的任何一个。
任何 C++ 标准都可以(最好是 C++17,但 C++20 也可以)。
澄清一下,我的真正目标是创建一个 Struct
,将两组可变参数传递给它以完美转发它们以初始化 member1
和 member2
。我认为将两个集合“分组”成元组可能是个好主意,因为那是 std::map::emplace
所做的。其他方法也可以工作(例如,在两组可变参数之间传递一个特殊对象)。
cppreference.com has a nice example of a sample implementation of std::make_from_tuple
,但是,正如您所发现的,由于缺少底层 class.[=14= 的复制构造函数,您无法使用它]
但是,它的面包屑导航可让您对其进行调整以解决这些限制:
#include <tuple>
#include <iostream>
struct Member1 {
Member1(int a, int b)
{
std::cout << a << " "
<< b
<< std::endl;
}
Member1(const Member1 &)=delete;
Member1(Member1 &&)=delete;
};
struct Member2 {
Member2(const char *str)
{
std::cout << str << std::endl;
}
Member2(const Member2 &)=delete;
Member2(Member2 &&)=delete;
};
// De-obfucation shortcut
template<typename Tuple>
using make_index_sequence_helper=std::make_index_sequence
<std::tuple_size_v<std::remove_reference_t<Tuple>>>;
struct Struct {
Member1 member1;
Member2 member2;
template<typename Tuple1, typename Tuple2>
Struct( Tuple1&& tuple1,
Tuple2&& tuple2 )
: Struct{std::forward<Tuple1>(tuple1),
make_index_sequence_helper<Tuple1>{},
std::forward<Tuple2>(tuple2),
make_index_sequence_helper<Tuple2>{}}
{
}
template<typename Tuple1, std::size_t ...tuple1_args,
typename Tuple2, std::size_t ...tuple2_args>
Struct(Tuple1 && tuple1,
std::index_sequence<tuple1_args...>,
Tuple2 && tuple2,
std::index_sequence<tuple2_args...>)
: member1{std::get<tuple1_args>(tuple1)...},
member2{std::get<tuple2_args>(tuple2)...}
{
}
};
int main()
{
Struct s{ std::tuple<int, int>{2, 3},
std::tuple<const char *>{"Hello world"}};
return 0;
}
使用 gcc 10 和 -std=c++17
进行测试。
std::make_from_tuple
确实是正确的选择:
#include <tuple>
struct Member1 {
Member1(int x,float y, char z){}
Member1(const Member1& other)=delete;
Member1(Member1&& other)=delete;
};
struct Member2 {
Member2(int x,float y, char z){}
Member2(const Member2& other)=delete;
Member2(Member2&& other)=delete;
};
struct Struct {
Member1 member1;
Member2 member2;
template<typename Tuple1, typename Tuple2>
Struct(Tuple1&& tuple1, Tuple2&& tuple2)
: member1(std::make_from_tuple<Member1>(std::forward<Tuple1>(tuple1))),
member2(std::make_from_tuple<Member2>(std::forward<Tuple2>(tuple2)))
{}
};
int main(){
Struct c(std::tuple{1,1.1,'c'},std::tuple{2,2.2,'x'});
}