提问人:darkspine 提问时间:11/1/2023 更新时间:11/2/2023 访问量:51
调用返回右值和左值元组混合的函数,而左值引用不会衰减为值?
Invoke functions that return a mix of rvalues and lvalue tuple without the lvalue references decaying into values?
问:
最小示例:
struct RValue {
int x = 12;
auto operator*() const { return x; }
} x;
struct LValueRef {
int y = 13;
auto &operator*() { return y; }
} y;
auto z = std::make_tuple(x, y);
auto f() {
// Replace std::make_tuple with what?
return std::apply([](auto &...x) { return std::make_tuple(*x...); }, z);
}
int main() {
auto [a, b] = f();
}
我希望 f 返回 a ,它当前返回 a .这应该在任意元组 z 上运行,其中取消引用的元素可以给出 r 值和 l 值引用。std::tuple<int, int&>
std::tuple<int, int>
最初,元组 z 的所有元素都类似于类,因此我过去常常以所需的形式返回元组。LValueRef
std::tie
我基本上需要调用 ,但将 a 包裹在最初是 l-vale 引用的元素周围。这可以按照以下伪代码所示完成:std::make_tuple
std::ref
if constexpr (std::is_lvalue_reference<T>::value)
return std::ref(t);
else
return t;
我不知道如何在调用中写这个,但也许我可以转换 的类型并创建返回std::apply
std::tuple
return std::tuple<Ts_transformed...>(*x...);
获得这种行为的理想方法是什么?
我短暂地尝试在不了解它如何工作的情况下使用(它编译了)。这导致 R 值成为 R 值引用,L 值成为 L 值引用(即,返回 .但是,在使用它时,我相信我在它超出范围后访问了一个临时文件,这是不正确的。我不确定这里到底发生了什么,为什么我不能使用这个值?std::forward_as_tuple
std::tuple<int &&, int &>
int &&
我最初试图编写一个类似于 Python 的适配器和 .我试图在上面编写的函数取消了对迭代器元组的引用。最初迭代器都返回左值引用,所以工作正常,但我希望它也适用于返回 rvalues 的迭代器。range
zip
std::tie
template <typename... WrappedRanges> class ZipWrappedRange {
std::tuple<WrappedRanges...> r_;
public:
class iterator {
std::tuple<typename WrappedRanges::iterator...> its_;
public:
explicit iterator(typename WrappedRanges::iterator &&...it) : its_(std::make_tuple(it...)) {}
explicit iterator(std::tuple<typename WrappedRanges::iterator...> &&it) : its_(it) {}
auto operator*() const {
// I need to modify this to allow for cases where (*x) returns rvalues and not just l-value references.
return std::apply([](auto &...x) { return std::tie((*x)...); }, its_);
}
};
...
}
答:
std::make_tuple
可能会替换为构造函数,其中显式提供类型:tuple
auto f() {
return std::apply([](auto&...x) { return std::tuple<decltype(*x)...>{*x...}; },
z);
}
使用 constexpr 包装器函数技巧的替代解决方案。
template <typename T> auto get_value(T &&t) {
if constexpr (std::is_lvalue_reference<T>::value)
return std::ref(t);
else
return t;
}
auto f() {
return std::apply([](auto &...x) { return std::make_tuple(get_value(*x)...); }, z);
}
评论
<ranges>
range-v3
<ranges>
constexpr
std::make_tuple(my_ref_wrapper(*x)...);