将二元组完美转换为一对
Perfectly transform a 2-tuple into a pair
我想要一个实用程序将 std::tuple<T,U>
转换为 std::pair<T,U>
,同时保持 std::tuple<T, U, V, W...>
不变。
此外,我希望此实用程序
- 是一个函数对象,而不是一个函数,这样我就可以随心所欲地传递它;
- 强制输入必须是
std::tuple
;
- 只要有可能就利用移动语义,这是有道理的。
最后一点对我来说是困难的部分,这也是我问这个问题的原因。
我知道元组可以存储值和引用(左值引用和右值引用),所以想象一下,如果使用右值 2 元组提供所寻找的函数,它可以从非参考组件,但应完整保留参考组件。
例如给定
A a;
B b;
std::tuple<A, B&> t{a,b};
我知道 a
被复制到元组中,而 b
不是,我认为这样做
auto p{to_pair(t)};
应该生成一个 std::pair<A, B&>
,其中包含 a
的另一个副本和对目前唯一存在的 b
的引用。
另一方面,做
B b;
auto p{to_pair(std::tuple<A, B&>{A{},b})};
应该会再次产生 std::pair<A, B&>
,但是这会保留 A{}
的内容,永远不应该制作任何副本;无论如何它都会引用 b
。
以上描述的场景已经足够让我犹豫不决了,更别提去想&
/const&
/&&
的其他组合了。
前段时间我有过一段苦日子,但我永远不能说我完全理解了他们。
template<class...Fs>
struct overloaded : Fs... {
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs&&...)->overloaded<std::decay_t<Fs>...>;
auto move_tuples = []<class...Ts>(std::tuple<Ts...> x){return std::move(x);};
auto to_pair = []<class A, class B>(std::tuple<A, B> x){
return std::pair<A,B>( std::get<0>(std::move(x)), std::get<1>(std::move(x)) );
};
auto your_function = overloaded{move_tuples, to_pair};
我想这就是你想要的。
我按值获取参数,然后将它们移动到 return 值。如果它们是值,则结果是移动包含的值。如果它们是引用,则它们不是,只是传播引用。
get<N>
在传递右值元组时“做正确的事”。如果 return 是一个值的右值。
在 c++17 中,您必须用手动结构替换 lambda。
或者写两个正常的重载,并且
auto obj=[](auto&&x)->decltype(normal_func(decltype(x)(x))){return decltype(x)(x);};
将重载函数调用normal_func
转换为单个函数对象。
我想要一个实用程序将 std::tuple<T,U>
转换为 std::pair<T,U>
,同时保持 std::tuple<T, U, V, W...>
不变。
此外,我希望此实用程序
- 是一个函数对象,而不是一个函数,这样我就可以随心所欲地传递它;
- 强制输入必须是
std::tuple
; - 只要有可能就利用移动语义,这是有道理的。
最后一点对我来说是困难的部分,这也是我问这个问题的原因。
我知道元组可以存储值和引用(左值引用和右值引用),所以想象一下,如果使用右值 2 元组提供所寻找的函数,它可以从非参考组件,但应完整保留参考组件。
例如给定
A a;
B b;
std::tuple<A, B&> t{a,b};
我知道 a
被复制到元组中,而 b
不是,我认为这样做
auto p{to_pair(t)};
应该生成一个 std::pair<A, B&>
,其中包含 a
的另一个副本和对目前唯一存在的 b
的引用。
另一方面,做
B b;
auto p{to_pair(std::tuple<A, B&>{A{},b})};
应该会再次产生 std::pair<A, B&>
,但是这会保留 A{}
的内容,永远不应该制作任何副本;无论如何它都会引用 b
。
以上描述的场景已经足够让我犹豫不决了,更别提去想&
/const&
/&&
的其他组合了。
前段时间我有过一段苦日子
template<class...Fs>
struct overloaded : Fs... {
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs&&...)->overloaded<std::decay_t<Fs>...>;
auto move_tuples = []<class...Ts>(std::tuple<Ts...> x){return std::move(x);};
auto to_pair = []<class A, class B>(std::tuple<A, B> x){
return std::pair<A,B>( std::get<0>(std::move(x)), std::get<1>(std::move(x)) );
};
auto your_function = overloaded{move_tuples, to_pair};
我想这就是你想要的。
我按值获取参数,然后将它们移动到 return 值。如果它们是值,则结果是移动包含的值。如果它们是引用,则它们不是,只是传播引用。
get<N>
在传递右值元组时“做正确的事”。如果 return 是一个值的右值。
在 c++17 中,您必须用手动结构替换 lambda。
或者写两个正常的重载,并且
auto obj=[](auto&&x)->decltype(normal_func(decltype(x)(x))){return decltype(x)(x);};
将重载函数调用normal_func
转换为单个函数对象。