在另一个对象构造函数中初始化不可复制的不可移动对象的数组

时间:2018-05-01 21:43:43

标签: c++ initializer-list systemc

这个问题与数组初始化和SystemC模块层次结构有关。

我有一个不可复制,不可移动,没有默认构造函数的类:

class Object : public sc_module {
    public:
      Object(string name, Configuration config);
      Object(const CPU& that) = delete;

};

和另一个包含这些数组的类:

class Object2 : public sc_module {
    public:
      std::array<Object, 2> obj_array;
      Object2() : obj_array <--??--> 
      {}
};

我需要使用obj_array初始化Objects,该class Object2: { public: std::array<Object, 2> obj_array; //note the double braces on this initializer list Object2() : obj_array {{ {"string1", config}, {"string2", config} }} {} }; 无法复制且无法移动。

我尝试了很多组合,编译的一件事就是:

Objects

它有效,但我在代码中看到了一些奇怪的行为:当我在obj_array中打印出Object2.string1的名称时,第一个是正确的Object2.string1.string2但是当它应该只是Object2.string2)时,下一个真的很奇怪arr

我知道很多人都提出了类似的问题,但我正在试图弄明白这里到底发生了什么。在我看来,我在初始化程序列表中有一个太多的括号,但它不会编译。否则就会编译。

使用g ++ 6.4.0和标志-std = c ++ 14

问题是如果我在构造函数的主体中创建另一个数组,例如     class Object2:{         上市:           std :: array obj_array;           //记下此初始值设定项列表中的双括号           Object2():obj_array {{{“string1”,config},{“string2”,config}}}           {               Obj arr [2] {{“test”,config},{“test2”,config}};           }     };

一切都好看。 .show.react-bs-table-sizePerPage-dropdown ul:last-child { display: block; } 对象名称和父母一样正确。

我知道这是一个深奥的问题,但我需要帮助了解我在obj_array初始化期间究竟发生了什么机制。

1 个答案:

答案 0 :(得分:3)

带有双括号的表单是初始化std::array的“完整”方式,因为std::array实际上是一个包含原始C样式数组的聚合结构。它基本上是

namespace std {
    template <class T, size_t N>
    struct array {
        T __some_internal_name[N];

        // public members...
    };
}

初始化如下:

std::array<int, 3> A{{ 2, 3, 4 }};

是有效的,因为外部{}用于std::array struct对象,而内部{}用于它包含的原始C样式数组。

但是通常是,你不需要加倍括号,因为有一条规则允许你在另一个聚合中省略聚合的一些嵌套大括号。这就是初始化的原因:

std::array<int, 3> A{ 2, 3, 4 };

与上述相同。

规则是,当编译器将初始化列表的各个部分与聚合的子对象(结构/类的非静态数据成员或数组元素)关联时,如果下一个子对象也是聚合(包含至少一个自己的子对象)并且初始化列表的下一部分不以{标记开头,然后子对象从初始化列表中获取尽可能多的部分,因为它具有自己的直接子对象。但是如果初始化列表中的下一个内容以{开头,则假定它是该聚合子对象的完整初始化列表。

所以如果你有几乎正确的代码

Object2() : obj_array { {"string1", config}, {"string2", config} }
   {}

编译器处理它是这样的:

  1. obj_array是一个std::array<Object, 2>,它是一个聚合结构,它的初始化程序是一个支撑初始化列表,因此聚合初始化适用。

  2. 第一个{obj_array对象相关联。

  3. obj_array有一个Object[2]类型的子对象。此类型也是聚合类型,初始化列表中的下一个内容以{开头,因此它会打开另一个初始化列表,用于初始化Object[2]数组。

  4. Object[2]包含两个类型为Object的子对象,它们是非聚合类类型。

  5. 第一个Object必须使用初始化列表中的下一个内容进行初始化,即"string1"。但是没有从const char[8]Object的有效转换。这是一个错误。

  6. 之后可能会出现其他错误,具体取决于编译器尝试继续的方式。

    简而言之,std::array的单括号样式在您的情况下不起作用的原因是因为您打算成为Object初始值设定项的开头是{ ,它被视为C风格数组的初始化器。

    双括号解决方案有效,或者您也可以指定Object类型以避免使用另一个初始化列表启动初始化列表元素:

    Object2() : obj_array { Object{"string1", config}, Object{"string2", config} }
       {}
    

    你的SystemC问题不太可能与所有这些有关,因为双支撑样式是正确的,并且会做你期望的。它可能是Configuration类的详细信息。 (请注意,您的构造函数使用Configuration参数“by value”,这意味着构造函数获取的对象将是您传递给它的任何内容的副本,如果这很重要。)我建议单独提出一个问题有关该问题的详细信息。