我遇到了这个代码
float range[] = { 0, 256 };
const float* histRange = { range };
对我来说,{ range }
的意思是"数组的数组",因为变量range
是浮点数组。因此,对我来说,这更有意义。
const float** histRange = { range };
但编译器(来自VS2019的VC++(不喜欢它(期望常量浮点*(
有人能向我解释一下为什么{range}
不是一个"数组数组"(float**(,而只是一个常规的浮点指针吗?
有趣的事实:当我做
float range[] = { 0, 256 };
auto aa = { range };
auto bb = range;
std::cout << typeid(aa).name() << std::endl;
std::cout << typeid(bb).name() << std::endl;
输出是(在VC++VS2019中(
std::initializer_list<float * __ptr64>
float * __ptr64
用大括号括起来的文本不是表达式,也没有类型。支持列表只允许在特定的上下文中使用,并且在每种情况下,语言定义都指定了以该支持列表为特征的较大上下文的语义。
行中:
const float* histRange = { range };
我们初始化的是标量,而不是数组。声明数组需要[]
语法。它不是定义一个未命名的数组,并且使histRange
指向该数组的第一个元素。
支撑列表作为标量(而不是auto
(的初始值设定项的含义是,列表必须包含0或1个元素;如果它包含1个元素,则行为与省略大括号的情况相同。
或者换句话说,标量的初始值设定项可以有大括号,例如int x = { 5 };
。这条规则自C.以来就一直存在
在这种情况下,不允许包含多个元素的支撑列表(尽管gcc默认情况下接受它并发出警告,并忽略除第一个元素之外的任何列表元素(。
因此,允许const float* histRange = range;
,因为range
是一个数组,并且存在从数组到指向该数组的第一个元素的指针的隐式转换,该元素具有类型float *
,并且还存在从float *
到const float *
的隐式转化。
const float** histRange = range;
将是一个错误(带或不带可选大括号(,因为没有从float *
到const float **
的转换。
还允许const float *histArr[1] = { range };
,它是指向常量float和长度1
的指针数组;在这里,你可以有一个有支撑的列表和更长的长度。
在auto aa = { range };
中,auto
的使用有其自己的类型推导规则,规则是该语法(声明符中没有*
或[]
(将aa
推导为具有一个元素的类型std::initializer_list<T>
。
注意,说{ range }
具有类型仍然是不正确的。std::initializer_list<T>
由支撑列表的元素初始化。
这个规则有点争议;在C++11中auto aa{range};
是相同的,但在C++17中它被改变为推断aa
与range
具有相同的类型。