初始化为const float*而不是const float**的数组数组



我遇到了这个代码

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中它被改变为推断aarange具有相同的类型。

最新更新