如何在不重复代码的情况下转发到两个重载之一?

How to forward to one of two overloads, without duplicating code?

我有一个 C++ class,其中有两个私有方法重载,它们应该连接到 public 方法的两个重载。

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

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

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

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;
    }
};

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

有没有办法避免代码重复,同时让 API 易于理解?

您可以添加额外的间接寻址来分解代码并拥有干净的界面:

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);
    }
};