почему вывод типа не работает, как ожидалось?

У меня есть небольшой вопрос о выводе типов в метапрограммировании C ++.
Есть определенная функция, выполняющая какое-то действие.

main.cpp

template<typename T> void foo(T arg) {
// do some action on argument
std::cout << typeid(arg).name() << std::endl;
}int main(int argc, char** argv) {
int array[100] = {0};
std::cout << typeid(array).name() << std::endl;
foo(array);

return 0;
}

Выход:

A100_i
Pi

Зачем Arg в функции Foo () иметь другой тип данных, чем массив в функции главный()?

0

Решение

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

void foo( int arg[100] );

язык требует, чтобы компилятор рассматривал это как:

void foo( int* arg );

100 это просто комментарий — он игнорируется
компилятор).

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

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

Так как эта поломка присутствует только по причинам
Совместимость с C, C ++ не следует этому, когда ссылки
участвует. Так:

template < typename T, size_t N >
void foo( T (&arg)[ N ] );

будет работать, и должен дать вам одинаковые результаты в обоих случаях.
Если вы думаете, что ваша функция может быть вызвана с
Массивы в стиле C и другие вещи (например, std :: vector), вы можете
перегрузить его для обоих. Версия выше более специализированная,
и будет предпочтительнее более общей версии, если это возможно.

Лучшим решением было бы полностью избежать массивов в стиле C, но
они полезны для статических переменных с инициализацией; его
только с массивами в стиле C, которые вы можете заставить рассчитывать компилятор
количество элементов и определить размер массива
согласно списку инициализатора. И иметь статический
инициализация; std::vector будет считать инициализаторы в
время выполнения, но используется как статическая переменная, может вызвать порядок
проблемы инициализации.
Массивы в стиле C и

3

Другие решения

На самом деле, когда вы передаете массив функции, он распадается на тип указателя. Так T выводитсяint*, вместо int[100],

Если вы хотите предотвратить затухание, примите параметр по ссылке.:

template<typename T> void foo(T & arg) //Note `&` here!
{
// do some action on argument
std::cout << (typeid(arg).name() << std::endl;
}

Теперь он напечатает то, что вы ожидаете, т.е. A100_i, Увидеть это онлайн демо.


Вопрос: почему массив переходит в тип указателя, когда мы передаем по значению?

Ответ: потому что в C ++ массивы (и функции) не могу пройти по значению. Язык не позволяет этого. Вместо этого язык требует, чтобы они превратились в указатель, когда они передаются в качестве аргументов функции. Чтобы предотвратить распад, мы должны передать их как ссылка.

6

По вопросам рекламы [email protected]