Массивы размера во время выполнения и распад указателя

Я тестировал некоторые инструменты в заголовке type_traits на новых массивах размера среды выполнения С++ 14, рассмотрим код ниже:

int g[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

template <typename T> void print(T &t)
{
    std::cout << "Type id:    " << typeid(T).name() << '\n';
    std::cout << "is_array:   " << std::is_array<decltype(T)>::value << '\n';
    std::cout << "is_pointer: " << std::is_pointer<decltype(T)>::value << '\n';
    std::cout << "extent:     " << std::extent<decltype(T)>::value << '\n';
}

int main()
{
    print(g);
    return 0;
}

Массив статического размера g возвращает следующий результат:

Type id:    A11_i
is_array:   1
is_pointer: 0
extent:     11

Неискаженное имя A11_i Я предполагаю, что это Aмассив 11 элементов типа int, поэтому здесь все правильно, но с этим новым кодом :

void f(std::size_t s)
{
    int a[s];
    print(a);
}

int main()
{
    f(5);
    return 0;
}

Я получаю ошибки:

In function 'void f(std::size_t)':
error: no matching function for call to 'print(int [s])'

note: candidate is:
note: template<class T> void print(T&)
note:   template argument deduction/substitution failed:
note:   variable-sized array type 'int [s]' is not a valid template argument

Я не ожидал, что аргумент размера может быть передан в шаблон, но я ожидал автоматического распада массива на указатель. Я предполагаю, что аргумент T & не подходит для такого распада, поэтому я попытался изменить подпись шаблона на:

template <typename T> void print(T *&t)

С аналогичными результатами:

In function 'void f(std::size_t)':
error: no matching function for call to 'print(int [s])'

note: candidate is:
note: template<class T> void print(T*&)
note:   template argument deduction/substitution failed:
note:   mismatched types 'T*' and 'int [s]'

И я заметил, что переменная размера в массиве размера времени выполнения кажется привязанной к типу (вместо mismatched types 'T*' and 'int [5]' мы получаем mismatched types 'T*' and 'int [s]') этого выглядит довольно странно.

Итак, в чем вопрос?

  • Почему я не получаю распад массива к указателю в этом массиве размера времени выполнения?
  • Используется ли переменная для определения размера массива размера среды выполнения, как часть типа массива размера среды выполнения, или я неправильно понимаю ошибку?

person PaperBirdMaster    schedule 13.04.2015    source источник
comment
Обратите внимание, что вы используете расширение VLA с int a[s];   -  person Jarod42    schedule 13.04.2015
comment
Многие флаги компилятора или нормы кода запрещают использовать массив размера времени выполнения. (например, я знаю, что G++ с предупреждающими флагами запрещает это). Возможно, ваш компилятор отказывается использовать его в качестве шаблона.   -  person Aracthor    schedule 13.04.2015
comment
Чтобы расширить комментарий Jarod42, были предложены массивы размера времени выполнения, но в конечном итоге они не были включены в окончательный стандарт С++ 14.   -  person eerorika    schedule 13.04.2015
comment
Виноват! Я действительно думаю, что массивы размера времени выполнения были включены в C++ 14 (поэтому я добавил тег C++ 14). В любом случае, это не меняет вопроса: почему VLA не распадается на указатель в этом примере?   -  person PaperBirdMaster    schedule 13.04.2015
comment
Работает ли он с массивом точного размера? Например, если вы проверите это с a[5]; вместо a[s]; ?   -  person Aracthor    schedule 13.04.2015
comment
Для распада на указатель вам нужно, чтобы тип параметра был T*, а не T*&. Последний будет работать только с фактическими указателями.   -  person interjay    schedule 13.04.2015
comment
@interjay Я тестировал T*, и он распался, поэтому, если вы ответите на комментарий (объясняя, почему T* распадается, а T*& нет), я приму ответ.   -  person PaperBirdMaster    schedule 13.04.2015
comment
[dcl.init.ref]/p5: обычные преобразования lvalue-to-rvalue (4.1), массив-указатель (4.2) и стандартные преобразования функции-указатель не нужны, и поэтому подавляются, когда выполняются такие прямые привязки к lvalue. Обратите внимание, что указатель, возвращенный из преобразования массива в указатель, будет значением r, поэтому он в любом случае не будет работать, если бы это произошло, поскольку вы не можете инициализировать неконстантную ссылку lvalue с помощью rvalue.   -  person 0x499602D2    schedule 13.04.2015


Ответы (1)


Во время вывода аргумента шаблона преобразование массива в указатель используется только в том случае, если тип параметра шаблона функции не является ссылкой.

§14.8.2.1 Вывод аргументов шаблона из вызова функции [temp.deduct.call]

1 Вывод аргумента шаблона выполняется путем сравнения каждого типа параметра шаблона функции (назовем его P) с типом соответствующего аргумента вызова (назовем его A), как описано ниже. [...]

2 Если P не является ссылочным типом:

  • Если A является типом массива, тип указателя, созданный стандартным преобразованием массива в указатель (4.2), используется вместо A для вывода типа; иначе,
  • [...]
person T.C.    schedule 13.04.2015