如何实现方便的初始化?

时间:2016-06-10 11:29:50

标签: c++ c++11 initialization

例如

#include <array>

class Range
{
public:
    Range(std::array<float, 2> ends) : m_ends(ends) {}

private:
    std::array<float, 2> m_ends;    
};

我可以

Range r({1, 2});

现在我有另一个班级

class Box
{
public:
    Box(std::array<Range, 3> ranges) : m_ranges(ranges) {}

private:
    std::array<Range, 3> m_ranges;    
};

我希望我能做到以下

Box b({{1,2}, {3,4}, {5,6}});

但我不能。如何更改代码以使其成为可能。

6 个答案:

答案 0 :(得分:4)

std::array有点奇怪。它没有用户定义的构造函数,所以它很像一个普通的结构。所以std::array<float,2>很像

struct two_floats {
   float array[2];
};

因此,如果你初始化一个,你会在逻辑上这样做:

two_floats          x = {{1,2}};
std::array<float,2> y = {{1,2}};

外部大括号用于结构本身,内部大括号用于结构的内容。

恰好只能提供一组大括号:

two_floats x = {1,2};

但这是由于C ++中的特殊规则允许在某些情况下省略大括号。类似于如何使用一组大括号初始化二维数组:

float x[2][2] = {1,2,3,4};

这就是你初始化你的范围时发生的事情:

Range r({1, 2});

相当于

std::array<float,2> arg = {1,2}; // one set of braces omittted
Range r(arg);

但哪个更明确地写成:

std::array<float,2> arg = {{1,2}};
Range r(arg);

初始化Box时会发生类似的事情。如果我们明确写出初始化,它将如下所示:

std::array<float,2> box_arg1 = {{1,2}};
std::array<float,2> box_arg2 = {{3,4}};
std::array<float,2> box_arg3 = {{5,6}};
std::array<Range,3> box_args = {{box_arg1,box_arg2,box_arg3}};
Box b(box_args);

因此,如果我们替换初始化器,我们得到:

Box b({{{{1,2}},{{3,4}},{{5,6}}}});

这是有效的。但它非常丑陋。这个初始化太复杂了,不允许在这里省略额外的括号,这就是你遇到的问题。

解决此问题的一种方法是提供其他构造函数来获取各个数组元素。

class Range
{
public:
    Range(float x,float y) : m_ends{x,y} { }
    Range(std::array<float, 2> ends) : m_ends(ends) {}

private:
    std::array<float, 2> m_ends;
};

class Box
{
public:
    Box(Range x,Range y,Range z) : m_ranges{x,y,z} {}
    Box(std::array<Range, 3> ranges) : m_ranges(ranges) {}

private:
    std::array<Range, 3> m_ranges;
};

现在你可以像你原来想要的那样初始化你的Box:

Box b({{1,2}, {3,4}, {5,6}});

答案 1 :(得分:3)

我只是删除数组并使用通常的字段。如果确实需要,您可以随时添加operator[]重载。只需将字段名称更改为您实际建模的内容。

class Range
{
public:
    Range(float x, float y) : m_x{x}, m_y{y}
    {}
private:
    float m_x, m_y; 
};

class Box
{
public:
    Box(Range w, Range h, Range d) : m_w{w}, m_h{h}, m_d{d}
    {}
private:
    Range m_w, m_h, m_d;
};

Live Demo

答案 2 :(得分:1)

<强>问题

此代码:Box b({{1,2}, {3,4}, {5,6}});正在尝试RangeRange个实例,即使Range不是聚合。

  

聚合初始化是列表初始化的一种形式,其中   初始化聚合

     

聚合是以下类型之一:

     

数组类型

     

类类型(通常是struct或union),具有

     

无   私有或受保护的非静态数据成员

     

没有用户提供的构造函数,包括从公共基础继承的那些   (从C ++ 17开始)(允许显式默认或删除构造函数)

     

(自C ++ 11以来)没有虚拟,私有或受保护(自C ++ 17)基础   课程

     

没有虚拟成员函数

<强>解决方案

显式调用std::array的构造函数,只聚合初始化Box b({Range({1,2}), Range({3,4}), Range({5,6})});

{{1}}

答案 3 :(得分:1)

您可以使用初始化列表:

class Range
{
public:
  Range(std::initializer_list<float> ends) : m_ends(ends) {}
  float a() {
    return m_ends[0];
  }
  float b() {
    return m_ends[1];
  }

private:
  std::vector<float> m_ends;
};

class Box
{
public:
  Box(std::initializer_list<Range> ranges) : m_ranges(ranges) {}

  void print()
  {
    for (auto& i : m_ranges)
    {
      std::cout << i.a() << "," << i.b() << std::endl;
    }
  }

private:
  std::vector<Range> m_ranges;
};


  Range r({ 1,2 });
  Box b({ {1,2},{3,4},{5,6} });
  b.print();

给出

1,2
3,4
5,6

答案 4 :(得分:0)

AFAIK无法用数组完成,你必须求助于基本类型

struct Range
{
    float m_ends[2] ;    
};


Range r = {1.0f, 2.0f};


struct Box
{
    Range m_ranges[3];    
};


Box b = {{{1.0f, 2.0f}, {1.0f, 2.0f}, {1.0f, 2.0f}}};

答案 5 :(得分:0)

要获得正确的初始化列表,请先列出其完整格式:

Box b{
    array<Range, 3>{{  // std::array needs aggregate-initialize, 
                       // and have to initialize a inner array
                       // without a addition '{', C++ is unable to
                       // know that the inner element is Range
        Range{
            {1, 2}  // short-hand for array<float>{{3, 4}}
        },
        Range{
            {3, 4}
        },
        Range{
            {5, 6}
        }
    }}
}

删除Box以外的所有类型,我们得到了:

Box b{ {{ {{1, 2}}, {{3, 4}}, {{5, 6}} }} }