Как переслать на одну из двух перегрузок, не дублируя код? - PullRequest
0 голосов
/ 09 января 2019

У меня есть класс 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 Ответ

0 голосов
/ 09 января 2019

Вы можете добавить дополнительную косвенность для факторизации кода и иметь чистый интерфейс:

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