为什么按值传递的数组上的 std::size 不起作用?

Bou*_*46i 5 c++ arrays pass-by-reference c++17

为什么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);
   // ...
}
Run Code Online (Sandbox Code Playgroud)

我正在打印尺寸,然后在我再次使用tab的子功能print_elemTab()中传递std::size()

没有得到匹配的函数错误,所以我想知道为什么std::size()第一次在test_tab()而不是在print_elemTab()

我必须通过引用传递它吗?那么我如何制作它,但对于任意长度的数组呢?

还是因为我不知道的事情我必须以另一种方式制作它?

Vla*_*cow 4

sizeof表达式中使用的数组指示符会隐式转换为指向其第一个元素的指针(极少数例外,例如在运算符中使用它们)。

所以在这次通话中

print_elemTab(tab);
Run Code Online (Sandbox Code Playgroud)

参数表达式的类型为int *

另一方面,具有数组类型的函数参数被编译器调整为指向数组的元素类型的指针。

例如这些函数声明

void     print_elemTab(int tab[]);
void     print_elemTab(int tab[5]);
void     print_elemTab(int tab[100]);
Run Code Online (Sandbox Code Playgroud)

声明相同的一个函数并且等价于下面的声明

void     print_elemTab(int *tab);
Run Code Online (Sandbox Code Playgroud)

您甚至可以在程序中包含所有这些声明,尽管编译器可以发出一条消息表明存在冗余声明。

因此,在函数中,您正在处理类型的指针int *。通常sizeof( int * )等于48取决于所使用的系统。

如果您有这样的声明,您应该更改它,指定第二个参数,该参数将保留传递数组中的元素数量,例如

void     print_elemTab(int *tab, size_t n );
Run Code Online (Sandbox Code Playgroud)

该函数可以这样调用

print_elemTab(tab, std::size( tab ) );
Run Code Online (Sandbox Code Playgroud)

另一种方法是通过引用传递数组。在这种情况下,您应该声明一个模板函数,例如

template <size_t N>
void     print_elemTab( int ( &tab )[N] );
Run Code Online (Sandbox Code Playgroud)

在函数中,您可以直接使用模板参数N作为数组中的元素数量。或者您可以将相同的标准 C++ 函数应用于std::size数组。

或者可以使用第二个模板类型参数来更通用地声明该函数,例如

template <typename T, size_t N>
void     print_elemTab( T ( &tab )[N] );
Run Code Online (Sandbox Code Playgroud)

另一种方法是将函数声明为

template <typename Container>
void     print_elemTab( Container &container );
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您还可以将标准函数应用于std::size参数容器。