为什么我不能像这样去盐化std::array?

7
为什么我不能像这样去除std::array中的盐分?
#include <array>

struct Point
{
    float x;
    float y;
};

int main()
{
   std::array<Point, 3> m_points { 
      { 1.0f, 1.0f }, 
      { 2.0f, 2.0f }, 
      { 3.0f, 3.0f }
   };
}

进行这样的操作会出现错误:

错误:std::array<Point,3ul> 的初始值设定项太多

但是按照以下方式可以正常工作:

std::array<Point, 3> m_points { 
   Point{ 1.0f, 1.0f }, 
   Point{ 2.0f, 2.0f }, 
   Point{ 3.0f, 3.0f } 
};

与之相反,std::map可以通过以下两种方式进行初始化:

   std::map<int, int> m1 {std::pair<int, int>{1,2}, std::pair<int, int>{3,4}}; 
   std::map<int, int> m2 {{1,2}, {3,4}};

2
花括号数量不对?尝试使用std::array<Point, 3> m_points {{{ 1.0f, 1.0f }, { 2.0f, 2.0f }, { 3.0f, 3.0f }}};看起来可以用... - ildjarn
我认为问题在于编译器不知道你想在第一个示例中初始化哪个结构体。即使你告诉数组类型,但它无法看到你想要的 Point - meetaig
3
这个上下文中我从未听说过"desalinize"这个词。我推断它的意思是"initialize"吗?(将"desalinize"翻译成中文可能需要根据具体情况而定,因为该词汇在中文中可能并不常见或存在替代词汇) - RedX
5
在这个语境中,"desalinize" 的意思是除去盐分,也就是将咸水变成淡水的过程。 - moooeeeep
3
@Narek,构造函数类型。std::array都是隐式声明的。std::map有一个接受std::initializer_list的构造函数。 - StoryTeller - Unslander Monica
显示剩余2条评论
2个回答

7
在这个声明和初始化中。
   std::array<Point, 3> m_points { 
      { 1.0f, 1.0f }, 
      { 2.0f, 2.0f }, 
      { 3.0f, 3.0f }
   };

编译器会将花括号中的第一个初始化值视为整个数组(内部聚合体)的初始化值。 std::array 是一个包含另一个聚合体的聚合体。
请改为:
   std::array<Point, 3> m_points {
      { 
      { 1.0f, 1.0f }, 
      { 2.0f, 2.0f }, 
      { 3.0f, 3.0f }
      }
   };

在第二种情况下
std::array<Point, 3> m_points { 
   Point{ 1.0f, 1.0f }, 
   Point{ 2.0f, 2.0f }, 
   Point{ 3.0f, 3.0f } 
};

每个初始化器被顺序地视为内部聚合的下一个元素的初始化器。

考虑这个简单的演示程序。

#include <iostream>

struct array
{
    int a[10];
};

int main()
{
    array a = { { 0, 0 }, { 1, 1 } };

    return 0;
}

编译器会提示类似以下的错误:
prog.cpp:14:33: error: too many initializers for 'array'
  array a = { { 0, 0 }, { 1, 1 } };
                                 ^

决定将{ 0, 0 }作为内部数组(内部聚合体)的初始化器。因此,花括号中的下一个初始化器在外部聚合体(结构体)中没有相应的数据成员。


我完全不明白为什么添加两个额外的花括号就能解决这个问题。 - Narek
@Narek,因为使用额外的大括号(或=)将进行聚合初始化。 - StoryTeller - Unslander Monica
@StoryTeller 或许一个类比的例子会更加清晰明了? - Narek
1
通常情况下,std::array被定义为包含一个数组的结构体。外部大括号内的第一个大括号被视为该数组的初始化器。当有多个大括号时,编译器会判断有更多的初始化器而不是聚合成员。 - Vlad from Moscow
为什么我必须处理std::array的内部实现?我只想初始化它,我不关心它是如何设计的。 - Narek
1
@Narek,因为标准将其定义为一个裸数组的轻量级容器,因此可以进行聚合初始化。上面链接的dup对此有很详细的描述。 - StoryTeller - Unslander Monica

3

std::array没有显式定义的构造函数,不像其他标准容器(如std::vectorstd::map),只有自动提供的构造函数。对于std::vector,编译器会尝试将表达式与每个可用的构造函数进行匹配,对于这样的构造:

std::vecor<Point> m_points { {1.0f,1.0f}, {2.0f,2.0f}, {3.0f,3.0f} };

找到与构造函数匹配的结果。
std::vector::vector(initializer_list<T>, const Allocator& = Allocator() );

但是在使用std::array时,它必须使用底层数组的聚合初始化(在您的情况下为 Point[3]),因此您的构造不匹配。要使其正常工作,您必须添加另一对大括号。

std::array<Point, 3> m_points { 
  { { 1.0f, 1.0f },
    { 2.0f, 2.0f }, 
    { 3.0f, 3.0f } }
};

为什么我必须处理std::array的内部实现?我只想初始化它,我不关心它是如何设计的。你同意这很糟糕吗? - Narek
这是另一个完全不同的问题。不要期望得到你最初没有提出的问题的答案。 - Walter
不在注释中吗? :) - Narek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接