语法重的多个lambda包装器的替代方法 - 如何避免样板代码?

时间:2016-05-04 13:58:04

标签: c++ lambda proxy refactoring c++14

我发现自己将多个lambdas封装在"代理"在我的代码的各个部分中具有更好界面的对象:

auto create_proxy()
{
    auto f_get_foo = [something]
    {
        return something_else();
    };

    auto f_set_bar = [something](auto x)
    {
        something_else(x);
    };

    auto f_render = [&window]
    {
        window.render();
    };

    return make_nice_proxy(   // .
        std::move(f_get_foo), // .
        std::move(f_set_bar), // .
        std::move(f_render));
}

我可以像这样使用代理:

nice_proxy.get_foo();    // calls the stored `f_get_foo` lambda
nice_proxy.set_foo(15);  // calls the stored `f_set_foo` lambda      
nice_proxy.render();     // calls the stored `f_render` lambda

问题是为这些代理编写和维护代码非常麻烦且语法很重:

template <             // .
    typename TFGetFoo, // .
    typename TFSetBar, // .
    typename TFRender  // .
    >
class nice_proxy_impl
{
// Hide the lambdas:
private:
    TFGetFoo _f_get_foo;
    TFSetBar _f_set_bar;
    TFRender _f_render;
    int _render_count = 0;

public:
    template <                // .
        typename TFwdFGetFoo, // .
        typename TFwdFSetBar, // .
        typename TFwdFRender  // .
        >
    nice_proxy_impl(             // .
        TFwdFGetFoo&& f_get_foo, // .
        TFwdFSetBar&& f_set_bar, // .
        TFwdFRender&& f_render)  // .
        : _f_get_foo(FWD(f_get_foo)),
          _f_set_bar(FWD(f_set_bar)),
          _f_render(FWD(f_render))
    {
    }

    // Expose the lambdas:
    void set_bar(int x)
    {
        some_side_effect();
        _f_set_bar(x);
    }

    auto get_foo() 
    { 
        return _f_get_foo(); 
    }

    void render() 
    {
        std::cout << "rendering...\n";
        _f_render();
        ++_render_count;
    }
};

template <typename... TFs>
auto make_nice_proxy(TFs&&... fs)
{
    return nice_proxy_impl<std::decay_t<TFs>...>(FWD(fs)...);
}

代理类的目的是:

  • 隐藏用户的lambda。
  • 为用户提供一个很好的(可能更丰富的)界面,通过这个界面他们可以调用&#34;隐藏&#34; lambda表达式。

我的代码库中有多个代理类,它们都私下存储一些完美转发的可调用对象(并通过public函数公开它们),并使用{{1}创建}} 功能。

虽然make_xxx_proxy通常易于实现且不需要太多维护,但每个代理类(如make_xxx_proxy每个函数需要一个模板参数,每个函数需要一个字段和一个完美转发构造函数参数。

使用多个代理类,甚至可以添加或删除单个&#34;封装的函数&#34;变得很烦人。 nice_proxy_implget_foo(以不同的形式)中重复nice_proxy_impl次。

对于这种&#34;模式&#34;是否有更好的,语法更重的解决方案?

我正在寻找一种避免常数lambda /函数重复的方法,键入衰减和完美转发,这只是样板。

如果传递的参数不仅是函数,而且还有附加字段,那么

make_xxx_proxy函数也会变得难以维护。在这种情况下不能使用参数扩展,并且每个函数都必须被衰减和转发。

此处make_xxx_proxya real examplethe corresponding proxy class功能。代理可能包含其他数据/方法,使用&#34;封装的lambdas&#34;以及各种方式的其他字段。这是css-tricks.com

1 个答案:

答案 0 :(得分:1)

我不确定我理解你的实际问题,但是你可以减少make_nice_proxy只返回一个本地成员(感谢C ++ 14)与公共成员(所以你可以聚合初始化)。这避免了重写大多数东西:

template <class Getter, class Setter, class Render>
auto make_nice_proxy(Getter&& g, Setter&& s, Render&& r)
{
    struct Proxy {
        std::decay_t<Getter> _f_get_foo;
        std::decay_t<Setter> _f_set_bar;
        std::decay_t<Render> _f_render;
        int _render_count = 0;

        void set_bar(int x) {
            some_side_effect();
            _f_set_bar(x);
        }

        auto get_foo() {
            return _f_get_foo();
        }

        void render() {
            std::cout << "rendering...\n";
            _f_render();
            ++_render_count;
        }
    };

    return Proxy{std::forward<Getter>(g), std::forward<Setter>(s), std::forward<Render>(r)};
}