【问题标题】:Perfectly transform a 2-tuple into a pair将一个 2 元组完美地转换为一对
【发布时间】:2021-05-15 05:46:18
【问题描述】:

我想要一个实用程序将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&lt;A, B&amp;&gt;,其中包含a 的另一个副本以及对目前唯一存在的b 的引用。

另一方面,做

B b;
auto p{to_pair(std::tuple<A, B&>{A{},b})};

应该再次生成std::pair&lt;A, B&amp;&gt;,但这将包含不应复制的A{};无论如何它都会引用b


上面描述的场景已经足以让我怀疑该怎么做,更不用说考虑&amp;/const&amp;/&amp;&amp;的其他组合了。

前段时间,answering a question about std::tuples and perfect forwarding 遇到了困难,但我永远不能说我已经完全理解了它们。

【问题讨论】:

  • 在后一个用例中,您必须至少移动 A{},因为它已经存在于tuple 中。可以吗?
  • @DavisHerring,如果你的意思是它从临时元组移动到非临时对,而不是在对中构建,那完全没问题。而且我怀疑这是我在不陷入无意义代码的情况下能做的最多的事情?还是不行?
  • std::make_from_tuple 不会为您完成几乎所有的工作吗?
  • 我不知道这个功能。应该会吧我会尽快检查的。
  • @DavisHerring,你的意思是 this?

标签: c++ tuples c++17 template-meta-programming perfect-forwarding


【解决方案1】:
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};

我想这就是你想要的。

我按值获取参数,然后将它们移至返回值。如果它们是值,则结果是移动包含的值。如果它们是引用,则不是,引用只是传播。

get&lt;N&gt; 在传递右值元组时“做正确的事”。如果从一个值返回一个右值。

中,您必须将 lambda 替换为手动结构。

或者写两个正常的重载,和

auto obj=[](auto&&x)->decltype(normal_func(decltype(x)(x))){return decltype(x)(x);};

将重载的函数调用normal_func 转换为单个函数对象。

【讨论】:

  • 一些反馈:1.模板参数列表是C++20的,不是C++17的,不过我猜是手写的structs解决了问题; 2. 你可以用boost::hana::overload 保存几行,从你的个人资料来看,我认为你很了解 Hana,所以我想知道你是否有意没有将其用于某些性能或其他原因; 3. this solution breaks down as soon as I start passing rvalue references template arguments to std::tuple.
  • 哦,关于上一条评论中的第三点,我实际上不知道为什么要这样做,但我的理由是:我可以写std::tuple&lt;int, int&amp;&amp;&gt; t{1,1};,并且我寻求的功能将允许执行 auto p = that_func(t); 这将导致 p 只是 2 元组的对版本;我不想再使用t,所以如果有必要,它最终可能会失效。
  • @enlico 制作了对存储参考。我看到不需要添加外部库依赖来节省 6 行。
  • 该问题未标记[boost],因此未要求提升解决方案。
  • @enlico 如果您保留并使用源元组目标,则如果没有复杂的语义,某些类型将无法得到合理的支持。如果你不是,那么总是移动。存储的值将被移动到返回值,在这种情况下转发引用。
猜你喜欢
  • 2016-08-06
  • 2021-03-31
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
  • 1970-01-01
  • 2018-08-27
  • 1970-01-01
相关资源
最近更新 更多