param-pack上的广义lambda捕获?

时间:2014-07-18 02:53:17

标签: c++ lambda c++14 variadic-functions

在C ++ 14中,广义lambda捕获让我们做:

template<class T>
auto pack(T t)
{
    return [t=std::move(t)](auto&& f){f(t);};
};

但它没有玩param-pack:

template<class... T>
auto pack(T... t)
{
    return [t=std::move(t)...](auto&& f){f(t...);};
};

是否有任何特殊语法或进一步的标准提案可以解决这个问题?

3 个答案:

答案 0 :(得分:18)

我的C ++ 14草案说([expr.prim.lambda] / 24):

  

simple-capture 后跟省略号是包扩展(14.5.3)。 init-capture 后跟省略号格式不正确。

所以看起来没有办法进行可变广义捕获。一种可能的解决方法是仅捕获元组中的参数,然后使用此处建议的解决方案之一:"unpacking" a tuple to call a matching function pointer

auto pack(T... t)
{
    return [args=make_tuple(std::move(t)...)](auto&& f){
               // find a way to call f with args
           };
};

修改

它现在被投票到C ++ 20,由proposal制作。虽然语法有点不同:

template<class... T>
auto pack(T... t)
{
    return [...t=std::move(t)](auto&& f){f(t...);};
};

请注意...在init-capture之前。

答案 1 :(得分:3)

作为后续行动,我来到了这个解决方法:

template<class T>
struct mover
{
    mover(T const& val) : val(val) {}

    mover(T&& val) : val(std::move(val)) {}

    mover(mover const& other) = default;

    mover(mover&& other) = default; 

    mover(mover& other) : val(std::move(other.val)) {}

    operator T const&() const
    {
        return val; 
    }

    T val;
};

template<class T>
using wrap_t = typename std::conditional
    <
        std::is_move_constructible<T>::value
    && !std::is_trivially_copy_constructible<T>::value
      , mover<T>
      , T
    >::type;

template<class... Ts>
auto pack_impl(wrap_t<Ts>... ts)
{
    return [=](auto&& f)->decltype(auto)
    {
        return f(static_cast<Ts const&>(ts)...);
    };
}

auto pack = [](auto&&... ts)
{
    return pack_impl<std::decay_t<decltype(ts)>...>(static_cast<decltype(ts)>(ts)...);
};

它利用mover作为代理,允许lambda通过移动捕获它(它有点hacky)。 wrap_t决定何时需要或有益于mover

现在我们可以测试一下:

struct A
{
    A() = default;

    A(A&&)
    {
        std::cout << "move\n";
    }

    A(A const&)
    {
        std::cout << "copy\n";
    }
};

A a;
std::cout <<"p1------------\n";
auto p1 = pack(std::move(a));
std::cout <<"p2------------\n";
auto p2 = std::move(p1);
std::cout <<"p3------------\n";
auto p3 = p2;

将打印:

p1------------
move
move
p2------------
move
p3------------
copy

答案 2 :(得分:3)

这扩展了我对上面Brian回答的评论。在带有库基础知识TS的C ++ 14中,您可以:

CREATE TRIGGER [TriggerName]
ON [Scope (Server|Database)]
FOR [EventName...],
AS
-- code for your trigger response here

假设您希望通过移动一般性地捕获参数包并在lambda中使用它,您可以在lambda中的lambda中编写代码,然后在其上应用参数:

template<class... T>
auto pack(T... t)
{
    return [ts = std::make_tuple(std::move(t)...)](auto&& f){
        std::experimental::apply(f, ts);
    };
};