提供初始化程序列表构造函数的有效方法

时间:2018-06-25 20:03:51

标签: c++ c++11 c++14 initializer-list perfect-forwarding

比方说,类Base具有以下解决方案:

struct Base
{
    int m_int;
    bool m_flag;
    float m_float;
    Base() = delete; // just to see that it didn't call
    Base(int a, bool b, float c): m_int(a), m_flag(b), m_float(c) {}

};

然后我有一个SubClass,该向量具有Base类的向量作为资源。

  • 研究后,我发现使用完美转发或转发 参考,Base类资源的创建效率很高,因为它避免了默认构造函数的不必要调用(请正确 我,如果我错了。
  • 除了转发技术外,我还希望有一个 初始化程序列表构造函数,这样我就可以进行汇总 SubClass

然后我为SubClass设计了以下代码。

struct SubClass
{
private:
    std::vector<Base> vec;
public:
    SubClass() = delete; // just to see that it didn't call

    // Idea - 1
    //SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

    // Idea - 2
    SubClass(std::initializer_list<Base> all): vec(all) {}

    // Idea - 3 : but no more list initialization possible
    template<typename ...Arg>
    void addToClass(Arg&& ...args)
    {
        vec.emplace_back(std::forward<Arg>(args)...);
    }
};

然后在main()中,我可以有以下两种可能性来更新SubClass中的资源:

int main()
{
    // possibility - 1
    SubClass obj
    {
       {1, true, 2.0f },
       {5, false, 7.0f},
       {7, false, 9.0f},
       {8, true, 0.0f},
    };
    //possibility - 2: without list initialization
    /*obj.addToClass(1, true, 2.0f);
    obj.addToClass(5, false, 7.0f);
    obj.addToClass(7, false, 9.0f);
    obj.addToClass(8, true, 0.0f);*/

    return 0;
}

问题-1:

在上述情况下,下列哪一项是有效的或易于使用(良好实践)?为什么?

// Idea - 1
SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

// Idea - 2
SubClass(std::initializer_list<Base> all): vec(all) {}

问题-2:

addToClass(Arg&& ...args)函数的工作原理与以上两个想法中的任何一个相似吗?

1 个答案:

答案 0 :(得分:1)

第一件事。

SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

SubClass(std::initializer_list<Base> all): vec(all) {}

不要做同样的事情。第一个还需要

SubClass(std::initializer_list<Base>& all): vec(all) {}

因此,您可以使用左值std::initializer_list对其进行初始化(可能永远不会发生,但是有可能)。通过值传递可以覆盖这两个重载,因此更容易编写,并且性能也差不多(需要很多操作才能真正发挥作用)

您不能将对象移出std::initializer_list,因为对象被标记为const,所以

SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

实际上没有移动任何东西。

对于addToClass,您可以同时拥有。您可以使用将单个对象包含到类中的模板版本。您还可以添加一个重载以使用std::initializer_list,以便可以添加多个对象,例如

void addToClass(std::initializer_list<Base> all)
{
    vec.insert(vec.end(), all.begin(), all.end());
}

,这会将all中的所有对象添加到vec的末尾。