std::apply 中的元组无法完美转发/移动构造
perfect forwarding / move construction isn't working from tuple in std::apply
我正在尝试使用嵌套的 lambda 捕获构建完美的转发(零复制)构造。
我希望应该有零复制结构,但有些东西坏了。
我从可变参数转移。打包到元组(移动正常)然后我将元组(移动正常)传递给 std::apply 并在最终嵌套的 lambda 中我 assemble 另一个元组(预计移动正常但 Wrapper CTOR 是 COPY 而不是 MOVE:
#include <iostream>
// tuple printer (ignore it)
template<typename Type, unsigned N, unsigned Last>
struct tuple_printer {
static void print(std::ostream& out, const Type& value) {
out << std::get<N>(value) << ", ";
tuple_printer<Type, N + 1, Last>::print(out, value);
}
};
template<typename Type, unsigned N>
struct tuple_printer<Type, N, N> {
static void print(std::ostream& out, const Type& value) {
out << std::get<N>(value);
}
};
template<typename... Types>
std::ostream& operator<<(std::ostream& out, const std::tuple<Types...>& value) {
out << "(";
tuple_printer<std::tuple<Types...>, 0, sizeof...(Types) - 1>::print(out, value);
out << ")";
return out;
}
// THE FUNCTION that returns lambda:
template <class ... Args>
auto f(Args && ... args)
{
// v--- args is a tuple<arg1, arg2, arg3 ...>
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]()
{
// v-- lower "args" is a restored list of arguments - moved from the upper tuple "args"
return std::apply([](auto && ... args) {
// v--- here the Wrapper COPY-CTOR is called instead of moved from
return std::make_tuple(std::forward<decltype(args)>(args)...);
}, std::move(args_upper));
};
}
struct Wrapper {
Wrapper() {
std::cout << "CTOR ";
}
Wrapper(const Wrapper & r) {
std::cout << "COPY-CTOR ";
}
Wrapper(Wrapper&& r) {
std::cout << "MOVE-CTOR ";
}
int w = 42;
friend std::ostream& operator<<(std::ostream& out, const Wrapper& w);
};
std::ostream& operator<<(std::ostream& out, const Wrapper& w) {
out << w.w;
return out;
}
int main() {
auto l = f(1,2.f,"st", Wrapper{});
auto t = l(); // t is tuple
std::cout << t; // tuple printer
// std::cout << l();
}
给出输出 CTOR MOVE-CTOR COPY-CTOR (1, 2, st, 42)
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]()
将此更改为
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]() mutable
args_upper
隐含地 const
除非你使你的 lambda mutable
。这将阻止移动语义。
我正在尝试使用嵌套的 lambda 捕获构建完美的转发(零复制)构造。 我希望应该有零复制结构,但有些东西坏了。
我从可变参数转移。打包到元组(移动正常)然后我将元组(移动正常)传递给 std::apply 并在最终嵌套的 lambda 中我 assemble 另一个元组(预计移动正常但 Wrapper CTOR 是 COPY 而不是 MOVE:
#include <iostream>
// tuple printer (ignore it)
template<typename Type, unsigned N, unsigned Last>
struct tuple_printer {
static void print(std::ostream& out, const Type& value) {
out << std::get<N>(value) << ", ";
tuple_printer<Type, N + 1, Last>::print(out, value);
}
};
template<typename Type, unsigned N>
struct tuple_printer<Type, N, N> {
static void print(std::ostream& out, const Type& value) {
out << std::get<N>(value);
}
};
template<typename... Types>
std::ostream& operator<<(std::ostream& out, const std::tuple<Types...>& value) {
out << "(";
tuple_printer<std::tuple<Types...>, 0, sizeof...(Types) - 1>::print(out, value);
out << ")";
return out;
}
// THE FUNCTION that returns lambda:
template <class ... Args>
auto f(Args && ... args)
{
// v--- args is a tuple<arg1, arg2, arg3 ...>
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]()
{
// v-- lower "args" is a restored list of arguments - moved from the upper tuple "args"
return std::apply([](auto && ... args) {
// v--- here the Wrapper COPY-CTOR is called instead of moved from
return std::make_tuple(std::forward<decltype(args)>(args)...);
}, std::move(args_upper));
};
}
struct Wrapper {
Wrapper() {
std::cout << "CTOR ";
}
Wrapper(const Wrapper & r) {
std::cout << "COPY-CTOR ";
}
Wrapper(Wrapper&& r) {
std::cout << "MOVE-CTOR ";
}
int w = 42;
friend std::ostream& operator<<(std::ostream& out, const Wrapper& w);
};
std::ostream& operator<<(std::ostream& out, const Wrapper& w) {
out << w.w;
return out;
}
int main() {
auto l = f(1,2.f,"st", Wrapper{});
auto t = l(); // t is tuple
std::cout << t; // tuple printer
// std::cout << l();
}
给出输出 CTOR MOVE-CTOR COPY-CTOR (1, 2, st, 42)
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]()
将此更改为
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]() mutable
args_upper
隐含地 const
除非你使你的 lambda mutable
。这将阻止移动语义。