结构化绑定和 tie()
Structured binding and tie()
鉴于这些声明:
int a[3] {10,20,30};
std::tuple<int,int,int> b {11,22,33};
我可以使用结构化绑定声明来解码 a
和 b
:
auto [x1,y1,z1] = a;
auto [x2,y2,z2] = b;
但是如果x1
、y1
等已经存在,我该怎么办?
std::tie(x1,y1,z1) = a; // ERROR
std::tie(x2,y2,z2) = b; // OK
这适用于 b
但不适用于 a
。是否有适用于 a
的类似简单构造,或者我是否必须分别获取 a[0]
、a[1]
和 a[2]
?
没有。
结构化绑定有特定的语言规则来处理数组和某些其他类型。 tie()
特别是一个 tuple<T&...>
并且只能从另一个 tuple<U&...>
.
赋值
对于数组的情况,您可以编写一个函数将该数组转换为引用的元组:
template <typename T, size_t N, size_t... Is>
auto as_tuple_impl(T (&arr)[N], std::index_sequence<Is...>) {
return std::forward_as_tuple(arr[Is]...);
}
template <typename T, size_t N>
auto as_tuple(T (&arr)[N]) {
return as_tuple_impl(arr, std::make_index_sequence<N>{});
}
std::tie(x1, y1, z1) = as_tuple(a); // ok
或者,如果您知道有多少绑定(无论如何您都必须知道),您可以使用结构化绑定作为返回元组。但是你必须指定大小并为每个写一个案例:
template <size_t I, typename T>
auto as_tuple(T&& tuple) {
if constexpr (I == 1) {
auto&& [a] = std::forward<T>(tuple);
return std::forward_as_tuple(a);
} else if constexpr (I == 2) {
auto&& [a, b] = std::forward<T>(tuple);
return std::forward_as_tuple(a, b);
} else if constexpr (I == 3) {
// etc.
}
}
std::tie(x1, y1, z1) = as_tuple<3>(a); // ok
只是为了好玩...模拟类似于
的语法
std::tie(x1,y1,z1) = a;
你可以编写一个结构来包装指针数组,operator=()
对应数组
template <typename T, std::size_t ... Is>
struct ptrArray<T, std::index_sequence<Is...>>
{
std::array<T*, sizeof...(Is)> ap;
auto & operator= (T (&arr)[sizeof...(Is)])
{
((*ap[Is] = arr[Is]), ...);
return *this;
}
};
和此结构的 make-function
template <typename T0, typename ... Ts>
ptrArray<T0, std::make_index_sequence<sizeof...(Ts)+1U>>
makePtrArray (T0 & t0, Ts & ... ts)
{ return { { { &t0, &ts... } } }; }
和
makePtrArray(x1, y1, z1) = a;
有效。
以下是完整的工作示例
#include <array>
#include <iostream>
#include <type_traits>
template <typename, typename>
struct ptrArray;
template <typename T, std::size_t ... Is>
struct ptrArray<T, std::index_sequence<Is...>>
{
std::array<T*, sizeof...(Is)> ap;
auto & operator= (T (&arr)[sizeof...(Is)])
{
((*ap[Is] = arr[Is]), ...);
return *this;
}
};
template <typename T0, typename ... Ts>
ptrArray<T0, std::make_index_sequence<sizeof...(Ts)+1U>>
makePtrArray (T0 & t0, Ts & ... ts)
{ return { { { &t0, &ts... } } }; }
int main ()
{
int x1, y1, z1;
int a[3] {10,20,30};
makePtrArray(x1, y1, z1) = a;
std::cout << x1 << ' ' << y1 << ' ' << z1 << std::endl;
}
鉴于这些声明:
int a[3] {10,20,30};
std::tuple<int,int,int> b {11,22,33};
我可以使用结构化绑定声明来解码 a
和 b
:
auto [x1,y1,z1] = a;
auto [x2,y2,z2] = b;
但是如果x1
、y1
等已经存在,我该怎么办?
std::tie(x1,y1,z1) = a; // ERROR
std::tie(x2,y2,z2) = b; // OK
这适用于 b
但不适用于 a
。是否有适用于 a
的类似简单构造,或者我是否必须分别获取 a[0]
、a[1]
和 a[2]
?
没有。
结构化绑定有特定的语言规则来处理数组和某些其他类型。 tie()
特别是一个 tuple<T&...>
并且只能从另一个 tuple<U&...>
.
对于数组的情况,您可以编写一个函数将该数组转换为引用的元组:
template <typename T, size_t N, size_t... Is>
auto as_tuple_impl(T (&arr)[N], std::index_sequence<Is...>) {
return std::forward_as_tuple(arr[Is]...);
}
template <typename T, size_t N>
auto as_tuple(T (&arr)[N]) {
return as_tuple_impl(arr, std::make_index_sequence<N>{});
}
std::tie(x1, y1, z1) = as_tuple(a); // ok
或者,如果您知道有多少绑定(无论如何您都必须知道),您可以使用结构化绑定作为返回元组。但是你必须指定大小并为每个写一个案例:
template <size_t I, typename T>
auto as_tuple(T&& tuple) {
if constexpr (I == 1) {
auto&& [a] = std::forward<T>(tuple);
return std::forward_as_tuple(a);
} else if constexpr (I == 2) {
auto&& [a, b] = std::forward<T>(tuple);
return std::forward_as_tuple(a, b);
} else if constexpr (I == 3) {
// etc.
}
}
std::tie(x1, y1, z1) = as_tuple<3>(a); // ok
只是为了好玩...模拟类似于
的语法std::tie(x1,y1,z1) = a;
你可以编写一个结构来包装指针数组,operator=()
对应数组
template <typename T, std::size_t ... Is>
struct ptrArray<T, std::index_sequence<Is...>>
{
std::array<T*, sizeof...(Is)> ap;
auto & operator= (T (&arr)[sizeof...(Is)])
{
((*ap[Is] = arr[Is]), ...);
return *this;
}
};
和此结构的 make-function
template <typename T0, typename ... Ts>
ptrArray<T0, std::make_index_sequence<sizeof...(Ts)+1U>>
makePtrArray (T0 & t0, Ts & ... ts)
{ return { { { &t0, &ts... } } }; }
和
makePtrArray(x1, y1, z1) = a;
有效。
以下是完整的工作示例
#include <array>
#include <iostream>
#include <type_traits>
template <typename, typename>
struct ptrArray;
template <typename T, std::size_t ... Is>
struct ptrArray<T, std::index_sequence<Is...>>
{
std::array<T*, sizeof...(Is)> ap;
auto & operator= (T (&arr)[sizeof...(Is)])
{
((*ap[Is] = arr[Is]), ...);
return *this;
}
};
template <typename T0, typename ... Ts>
ptrArray<T0, std::make_index_sequence<sizeof...(Ts)+1U>>
makePtrArray (T0 & t0, Ts & ... ts)
{ return { { { &t0, &ts... } } }; }
int main ()
{
int x1, y1, z1;
int a[3] {10,20,30};
makePtrArray(x1, y1, z1) = a;
std::cout << x1 << ' ' << y1 << ' ' << z1 << std::endl;
}