What is the type of inline array?

When outputting a template parameter of a non-type type, say n , the types n must exactly match between the parameter and the argument. Thus, the following code will not compile (at least on GCC and clang):

 #include <array> template <int n> void f(std::array<int, n> const&) {} int main() { std::array<int, 3> arr; f(arr); } 

This is because std::array declared as

 template <typename T, std::size_t n> class array; 

but not

 template <typename T, int n> class array; 

However, to fix the size of the inline array, it seems that any integral type does. All of the following work on GCC, clang, and VC ++:

 template <typename T, char n > void f(T (&)[n]); template <typename T, short n> void f(T (&)[n]); template <typename T, int n> void f(T (&)[n]); ... 

So seriously, is the built-in array size type overloaded?

+6
source share
3 answers

This is described in clause 14.8.2.5 [temp.deduct.type] :

17 - [...] [Template type] must exactly match the type of the template parameter, except that the template argument deduced from the array binding can be of any integer type.

At http://wg21.cmeerw.net/cwg/issue1770 this is improved to a more general one:

17 - If P has a form containing <i> , and if the type of the corresponding value of A is different from type i , then the output is not performed. If P has a form containing [i] , and if type i not an integral type, then no inference is made.

Thus, the boundaries of the array can be inferred to any integral type, but the template parameters of the non-pig type must be inferred to the actual type in the template definition.

In fact, nowhere in the C ++ 11 standard version does the preferred type for the boundaries of the array be specified; the boundary of the array is specified (in [dcl.array] ) as "an integral constant expression, and its value must be greater than zero". In recent projects for C ++ 14, this changes to "a converted constant expression (5.19) of the type std::size_t [...]"; the changed definition can be traced back to n3306 . Oddly enough, the change is presented as a "consistent adjustment [..] for consistency", implying that editors take for granted that size_t was the right type.

+4
source

From Β§8.3.4 [dcl.array] / 1:

If the constant expression (5.19), it must be a converted constant expression of the type std :: size_t, and its value must be greater than zero. The constant expression defines the boundary (number of elements) of the array

Type std::size_t .

The reason other types work in general is because conversions are performed according to the type passed in accordance with Β§14.3.2 [temp.arg.nontype] / 5:

For a template template that is not a type of an integral or enumerated type, the transformations allowed in the transformed constant expression (5.19) are applied.

From Β§5.19 [expr.const] / 3:

An integral constant expression is an expression of an integral or non-enumerated type of enumeration implicitly converted to prvalue, where the converted expression is an expression of a constant constant.

snip (mentions that they can be used as array boundaries)

A converted constant expression of type T is an expression implicitly converted to a prvalue of type T, where the converted expression is an expression of a constant constant, and the implicit conversion sequence contains only user-defined transformations, lvalue-to-rvalue transforms (4.1), integral advancements (4.5) and integral conversions (4.7), except for narrowing conversions (8.5.4).

Finally, Β§4.7 [conv.integral] / 3:

If the destination type is signed, the value does not change if it can be represented in the destination type (and bit width); otherwise, the value is determined by the implementation.

If the binding value is placed inside your parameter type, it will be successfully converted. If not, you will end up with a specific value for the binding.

Arrays are a special case, as stated in ectamur's answer :

Β§14.8.2.5 [temp.deduct.type] / 17:

If, in a function template declaration with a non-character parameter template, a non-type parameter parameter is used in the expression in the function parameter list and, if the corresponding argument template is output, the template template type must exactly match the parameter template type, except that the argument is the template deduced from the array binding can be of any integral type.

+6
source

The size of the C array is a compile-time constant and is controlled by the compiler (there is no information about the size of the C array at runtime), when you create an instance of the template, the compiler only checks to see if the actual type matches the specified size. Example:

 template <typename T, char n > void f(T (&)[n]) {} int main() { int a[1000]; f(a); } 

This will happen even if int a[20]; will succeed.

0
source

Source: https://habr.com/ru/post/972455/


All Articles