完美的转发/移动构造不适用于std :: apply中的元组

bar*_*ney 3 c++ lambda templates variadic-templates perfect-forwarding

我正在尝试使用嵌套的lambda捕获构造完美的转发(零复制)构造.我希望应该有零复制结构,但有些东西被打破了.

我从variadic arg移动.打包到元组(移动确定)然后我将元组(移动确定)传递给std :: apply并在最终嵌套的lambda中我组装另一个元组(预计移动正常但是Wrapper CTOR是COPY而不是移动:

#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();
}
Run Code Online (Sandbox Code Playgroud)

输出CTOR MOVE-CTOR COPY-CTOR(1,2,st,42)

Yak*_*ont 9

return [args_upper = std::make_tuple(std::forward<Args>(args)...)]()
Run Code Online (Sandbox Code Playgroud)

将此更改为

return [args_upper = std::make_tuple(std::forward<Args>(args)...)]() mutable
Run Code Online (Sandbox Code Playgroud)

args_upperconst除非你做你的lambda,否则是隐含的mutable.这将阻止移动语义.

  • @barney我认为"好吧,你正在试图移动而且它正在复制.这可能意味着你搞砸了完美的转发 - 一些参考文献的价值.嗯,不,看起来你的价值是正确的.好吧,接下来可能性是你想要从'企业'移动.Ayep,就在那里." 像大多数事情一样,这是一个以前犯过这个错误的问题. (2认同)