Почему std :: size в массиве, переданном по значению, не работает? - PullRequest
5 голосов
/ 20 июня 2020

Почему std::size() не работает со статически распределенным массивом, переданным по значению?

void print_elemTab(int tab[])
{
   // ...
   int size = std::size(tab); //error 
   // ...
}

void test_tab()
{
   const int    TAB_SIZE = 5;
   int          tab[TAB_SIZE] = {};
   // ...
   cout << std::size(tab) << std::endl; //print 5
   print_elemTab(tab);
   // ...
}

Я печатаю размер, а затем передаю tab в подфункции print_elemTab(), где я снова использую std::size().

Я получаю нет функции сопоставления ошибка, поэтому мне интересно, почему std::size() работает в первый раз в test_tab(), а не в print_elemTab()

Надо ли передавать по ссылке? Итак, как мне это сделать, кроме массива любой длины?

Или мне нужно сделать это по-другому из-за чего-то, о чем я не знаю?

Ответы [ 3 ]

3 голосов
/ 20 июня 2020

Надо ли передавать по ссылке? Итак, как мне это сделать, но для любого массива любой длины?

Да , передача его по ссылке была бы одним из вариантов.

template<std::size_t n>
void print_elemTab(int (&tab)[N]) // const int (&tab)[N], if the elements won't be modified
{
    std::cout << N << "\n"; // where you can directly get the size `N`
}

Или как простая шаблонная функция, как показано ниже

template<typename T>
void  print_elemTab(T& tab)// const T& tab, if the elements won't be modified
{
   const auto size = std::size(tab);
   std::cout << size << "\n";
}

Другой вариант - вывести массив до его фактического типа. В вашем случае tab имеет тип int[5]. Компилятор может определить свой фактический тип (отличный от перехода на указатель), если вы полностью перешлите через функцию-шаблон.

#include <iostream>
#include <array>

template<typename T>
void  print_elemTab(T&& tab)
{
   const auto size = std::size(tab);  // now you can do std::size() on the int[size]
   std::cout << size << "\n";
}
3 голосов
/ 20 июня 2020

Указатели массивов, используемые в выражениях, неявно преобразуются (за редкими исключениями, например, при использовании их в операторе sizeof) в указатели на их первые элементы.

Итак, в этом вызове

print_elemTab(tab);

выражение аргумента имеет тип int *.

С другой стороны, параметр функции, имеющий тип массива, корректируется компилятором на указатель на тип элемента массива.

Так, например, эти объявления функций

void     print_elemTab(int tab[]);
void     print_elemTab(int tab[5]);
void     print_elemTab(int tab[100]);

объявляют одну и ту же функцию и эквивалентны следующему объявлению

void     print_elemTab(int *tab);

Вы даже не можете включить все эти объявления в свою программу, хотя компилятор может выдать сообщение о наличии избыточных объявлений.

Следовательно, внутри функции вы имеете дело с указателем типа int *. И sizeof( int * ) обычно равно 4 или 8 в зависимости от используемой системы.

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

void     print_elemTab(int *tab, size_t n );

И функция может вызываться как

print_elemTab(tab, std::size( tab ) );

Другой подход - передать массив по ссылке. В этом случае вы должны объявить шаблонную функцию, например, как

template <size_t N>
void     print_elemTab( int ( &tab )[N] );

Внутри функции вы можете либо напрямую использовать параметр шаблона N как количество элементов в массиве. Или вы можете применить к массиву ту же стандартную функцию C ++ std::size.

Или функция может быть еще более общей, объявленной со вторым параметром типа шаблона, например

template <typename T, size_t N>
void     print_elemTab( T ( &tab )[N] );

Другой подход - для объявления функции типа

template <typename Container>
void     print_elemTab( Container &container );

В этом случае вы также можете применить стандартную функцию std::size к контейнеру параметров.

2 голосов
/ 20 июня 2020

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

#include <iostream>

template<size_t n>
void print_elemTab(int (&tab)[n])
{
    int size = std::size(tab);
    std::cout << size << "\n";// or just  std::cout << n; and ignore the previous line 
}
    
void test_tab() {
    const int TAB_SIZE = 5;
    int tab[TAB_SIZE] = {};
    std::cout << std::size(tab) << std::endl; //print 5
    print_elemTab(tab);
    
}
    
int main(){
    test_tab();
}

 
...