【问题标题】:Mimic std::bind_front in c++17 for calling member functions模仿 c++17 中的 std::bind_front 调用成员函数
【发布时间】:2021-02-19 02:02:37
【问题描述】:

是否有可能在 C++17 中轻松模仿 std::bind_front ? (仅用于成员函数包装就可以了)

我查看了 中的实现,旨在复制,但它似乎确实非常特定于实现。

我在想 lambda 包装器或模板函数/对象可能有用吗?

(性能在这里不是问题)

【问题讨论】:

  • 是的,这是可能的。例如,可以使用 lambda,或将绑定参数存储在元组中的专用类。

标签: c++20 c++ c++17 template-meta-programming higher-order-functions bind-front


【解决方案1】:

这可以作为一个起点

template<typename F, typename ...FrontArgs>
struct bindfronthelper
{
    bindfronthelper(F f, FrontArgs&&...args)
        : mF{std::move(f)}
        , mFrontArg{std::forward<FrontArgs>(args)...}
    {}

    template<typename ...BackArgs>
    auto operator()(BackArgs&&...args) const
    {
        return std::apply(mF, std::tuple_cat(mFrontArg, std::forward_as_tuple(args...)));
    }

    F mF;
    std::tuple<std::decay_t<FrontArgs>...> mFrontArg;
};

template<typename F, typename ...FrontArgs>
auto mybindfront(F f, FrontArgs&&...args)
{
    return bindfronthelper<F, FrontArgs...>{std::move(f), std::forward<FrontArgs>(args)...};
}

https://godbolt.org/z/Tz9fen

写得很快,没有经过很好的测试,所以在极端情况下可能会有一些陷阱。至少它显示了如何实现这一点。


好吧,我把这个弄得太复杂了,这里是更简单的版本:

template<typename T, typename ...Args>
auto tuple_append(T&& t, Args&&...args)
{
    return std::tuple_cat(
        std::forward<T>(t),
        std::forward_as_tuple(args...)
    );
}

template<typename F, typename ...FrontArgs>
decltype(auto) mybindfront(F&& f, FrontArgs&&...frontArgs)
{
    return [f=std::forward<F>(f), 
            frontArgs = std::make_tuple(std::forward<FrontArgs>(frontArgs)...)]
            (auto&&...backArgs) 
        {
            return std::apply(
                f, 
                tuple_append(
                    frontArgs, 
                    std::forward<decltype(backArgs)>(backArgs)...)); 
        };
}

https://godbolt.org/z/cqPjTY

仍然通过了我提供的所有测试。我保留了旧版本,因为通过一些工作可以对其进行调整以使用旧标准的 c++。

【讨论】:

  • 警告是价值类别,首先保持参考而不是复制。 lamdba 会复制而不是移动以进行捕获。
【解决方案2】:

我发现一种非常简单的方法是使用 lambda(在这种情况下捕获 this - 但您可以轻松地将其更改为普遍采用):

auto bind_m = [this](auto mem_f) {
    auto wrapper = [=] (auto&&... args) {return std::mem_fn(mem_f)(this, std::forward<decltype(args)>(args)...);};
    return wrapper;
};

lambda 创建另一个 lambda 并返回它。

【讨论】:

  • @MarekR 是的,你指的是哪一部分?
  • 查看我在答案中提供的测试并尝试通过您的解决方案。
  • @MarekR 看起来很棒,而且 ty !!,但正在寻找代码占用空间更小的东西,也只是用于成员函数包装。
【解决方案3】:
template<typename F, typename... FRONT_ARGS>
    auto bind_front(F&& f, FRONT_ARGS&&... front_args)
    {
        // front_args are copied because multiple invocations of this closure are possible
        return [captured_f = std::forward<F>(f), front_args...](auto&&... back_args) {
                   return std::invoke(captured_f, front_args...,
                                      std::forward<decltype(back_args)>(back_args)...);
               };
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    相关资源
    最近更新 更多