【问题标题】:How to forward to one of two overloads, without duplicating code?如何在不重复代码的情况下转发到两个重载之一?
【发布时间】:2019-01-09 17:25:02
【问题描述】:

我有一个带有两个私有方法重载的 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 易于理解?

【问题讨论】:

  • 回复:“你必须检查公共方法的主体......”只有在文档没有充分解释如何使用该类的情况下。
  • @PeteBecker:我不同意。如果您以标准库为例,在可变参数模板/完美转发的每种情况下,您都可以使用函数或类型上的可用模板参数来确定哪些参数是合法的。 make_shared&lt;T&gt; 接受 T 的构造函数所接受的任何内容。 std::function&lt;FuncType&gt;::operator() 接受FuncType 的参数。等等。如果你只是有一个像这样的裸函数,这些参数背后没有明显的含义,那么假设该函数将采用任何东西,或者任何符合某些概念的东西。
  • 其实我更喜欢你的第二个版本。恕我直言,更容易识别它的作用。难道你不能通过使它们都调用相同的私有帮助方法的“蹦床”来防止代码重复吗?
  • @NicolBolas -- 我对标准库的规范非常熟悉。您不必通过实现来查看它的作用。是的,该标准使用模板参数的名称来提供部分规范;这一切都在标准中明确说明,即在文档中。在某些情况下(尽管这些正在慢慢被删除),该标准使用代码作为行为的规范,但它没有指定要求
  • @NicolBolas -- 更直截了当地说明我的原点:如果你必须阅读代码才能弄清楚需求是什么,那么类设计器就失败了。

标签: c++ c++14 overloading perfect-forwarding


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-11
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    相关资源
    最近更新 更多