c++ - 提供初始化列表构造函数的有效方法

标签 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 类的 vector 作为资源。

  • 经过研究我发现使用完美转发或转发 引用,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) 函数是否与上述两个想法中的任何一个类似?

最佳答案

要事第一。

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 的末尾。

关于c++ - 提供初始化列表构造函数的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51031072/

相关文章:

c++ - 单向链表,为什么链表是空的(head == NULL)?

c++ - 在 C++ 中保持对函数返回值的引用

c++ - 是否可以在 C++14 中分配和验证 constexpr 结构?

c++ - 重新打开一个关闭的文件流

c++ - 创建一个将另一个 CMap 作为值的 CMap

c++ - 将指针传递给函数 - 为什么我不能打印地址?

C++ 对重载函数的引用不明确

c++ - 计算嵌套包中的类型总数

c++ - 使用默认容器,但在 priority_queue 中使用自定义比较器

c++ - 如何在使用算法保持原始排序的同时从未排序的 std::vector 中删除重复项?