Text enclosed by braces is not an expression, and doesn't have a type. A braced list is only allowed in certain contexts, and in each case the language definition specifies the semantics of the larger context featuring that braced list.
In the line:
const float* histRange = { range };
we are initializing a scalar, not an array. The [] syntax is required to declare an array. It is not defining an unnamed array and having histRange point to the first element of that array.
The meaning of a braced list as initializer for a scalar (other than auto) is that the list must contain 0 or 1 elements; and if it contains 1 element then the behaviour is the same as if the braces were omitted.
Or in other words, initializers for scalars can optionally have braces, e.g. int x = { 5 };. This rule has been around since C.
A braced list with more than one element would not be allowed in this context (although gcc accepts it with a warning by default, and ignores any list elements besides the first).
So, const float* histRange = range; is allowed because range is an array, and there is an implicit conversion from array to pointer-to-first-element-of-that-array, which has type float *, and there is also implicit conversion from float * to const float *.
const float** histRange = range; would be an error (with or without optional braces) because there is no conversion from float * to const float **.
Also allowed would be const float *histArr[1] = { range }; which is an array of pointers to const float and length 1; here you could have a braced list and a longer length.
In auto aa = { range }; , the use of auto has its own rules of type deduction, and the rule is that this syntax (without * or [] in the declarator) deduces aa as having type std::initializer_list<T> of one element.
Note that it would still not be correct to say that { range } has a type. The std::initializer_list<T> is initialized by the elements of the braced list.
This rule is slightly controversial; in C++11 auto aa{range}; was the same, but in C++17 it was changed to deduce aa to have the same type as range.
float* range = { 0, 256 };and this will:const float* histRange[] = { range };This is because{ 0, 256 }and{ range }are not arrays that you can point to, they are lists of values ready to initialize arrays. Pedantically,std::initializer_list<T>doesn't decay to aT*the same way that a realT[]does.std::initializer_listexcept in certain contexts, which this is not one of