代码之家  ›  专栏  ›  技术社区  ›  ptomato

如何转发到两个重载之一,而不复制代码?

  •  0
  • ptomato  · 技术社区  · 6 年前

    我有一个C++类,有两个重载的私有方法,并且那些应该连接到公共方法的两个重载。

    公共方法在两个重载中都是相同的,它只在它调用的私有方法的重载中有所不同。另一方面,这两个私有方法重载是完全不同的,这就是为什么我首先选择重载它们。

    为了避免在公共方法中重复代码,这似乎是完美转发的一个很好的用例。但是,另一方面,如果您想调用公共方法而不熟悉API,就很难看到必须提供哪些参数;您必须检查公共方法的主体,然后咨询私有接口,以查看私有方法存在哪些重载。

    我试着做一个玩具课来说明我的问题:

    class Foo {
    public:
        struct DontCopyTheBaz {};
    
    private:
        bool init_from_baz(Baz& a_baz);
        bool init_from_baz(Baz& a_baz, DontCopyTheBaz);
    
    public:
        // ...should I use perfect forwarding, making the API not easily readable?
        template<typename... Args>
        static Foo* new_for_baz(Baz& a_baz, Args&&... args) {
            Foo* the_foo = new Foo();
            if (!the_foo->init_from_baz(a_baz, std::forward<Args>(args)...)) {
                delete the_foo;
                return nullptr;
            }
            return the_foo;
        }
    
        // ...or should I write duplicated code?
        static Foo* new_for_baz(Baz& a_baz) {
            Foo* the_foo = new Foo();
            if (!the_foo->init_from_baz(a_baz)) {
                delete the_foo;
                return nullptr;
            }
            return the_foo;
        }
        static Foo* new_for_baz(Baz& a_baz, DontCopyTheBaz no_copy) {
            Foo* the_foo = new Foo();
            if (!the_foo->init_from_baz(a_baz, no_copy)) {
                delete the_foo;
                return nullptr;
            }
            return the_foo;
        }
    };
    

    (实际上,私有方法和公共方法都更长更复杂。)

    有没有一种方法可以避免代码重复,同时仍使API易于理解?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Jarod42    6 年前

    您可以添加额外的间接性来分解代码并具有干净的接口:

    class Foo {
    public:
        struct DontCopyTheBaz {};
    
    private:
        bool init_from_baz(Baz& a_baz);
        bool init_from_baz(Baz& a_baz, DontCopyTheBaz);
    
        template<typename... Args>
        static std::unique_ptr<Foo> new_for_baz_impl(Baz& a_baz, Args&&... args) {
            auto the_foo = std::make_unique<Foo>();
            if (!the_foo->init_from_baz(a_baz, std::forward<Args>(args)...)) {
                return nullptr;
            }
            return the_foo;
        }
    
    public:
        static std::unique_ptr<Foo> new_for_baz(Baz& a_baz) {
            return new_for_baz_impl(a_baz);
        }
        static std::unique_ptr<Foo> new_for_baz(Baz& a_baz, DontCopyTheBaz no_copy) {
            return new_for_baz_impl(a_baz, no_copy);
        }
    };