无法在一个程序中使用 std::size()

Not able to use std::size() in one program

我正在使用数组。所以要找到数组的大小,我需要使用 std::size(),它在一个程序中运行良好但在另一个程序中无法运行。

有效的程序:

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    int array[]{ 30, 50, 20, 10, 40};
    std::sort(std::begin(array), std::end(array));

    for (int i{0}; i < static_cast<int>(std::size(array)); ++i)
    {
        std::cout << array[i] << '\t';
    }

    std::cout << '\n';

    return 0;
}

输出:

10      20      30      40      50

无法运行的程序:

#include <iostream>
#include <iterator> // for std::size() but not working yet

void splitInteger(int integer, int components[])
{   
    int count{0};

    do
    {
        int element{ integer % 10 };
        components[count] = element;

        integer = integer / 10;
        ++count;
    }
    while(integer != 0);

}
int main()
{
    int num{};                  
    std::cin >> num;

    int components[]{};         
    splitInteger(num, components);

    std::cout << std::size(components) << '\n';
    return 0;
}

编译报错如下:

tempCodeRunnerFile.cpp: In function ‘int main()’:
tempCodeRunnerFile.cpp:38:38: error: no matching function for call to ‘size(int [0])’
   38 |     std::cout << std::size(components) << '\n';
      |                                      ^
In file included from /usr/include/c++/9/string:54,
                 from /usr/include/c++/9/bits/locale_classes.h:40,
                 from /usr/include/c++/9/bits/ios_base.h:41,
                 from /usr/include/c++/9/ios:42,
                 from /usr/include/c++/9/ostream:38,
                 from /usr/include/c++/9/iostream:39,
                 from tempCodeRunnerFile.cpp:1:
/usr/include/c++/9/bits/range_access.h:242:5: note: candidate: ‘template<class _Container> constexpr decltype (__cont.size()) std::size(const _Container&)’
  242 |     size(const _Container& __cont) noexcept(noexcept(__cont.size()))
      |     ^~~~
/usr/include/c++/9/bits/range_access.h:242:5: note:   template argument deduction/substitution failed:
/usr/include/c++/9/bits/range_access.h: In substitution of ‘template<class _Container> constexpr decltype (__cont.size()) std::size(const _Container&) [with _Container = int [0]]’:
tempCodeRunnerFile.cpp:38:38:   required from here
/usr/include/c++/9/bits/range_access.h:243:24: error: request for member ‘size’ in ‘__cont’, which is of non-class type ‘const int [0]’
  243 |     -> decltype(__cont.size())
      |                 ~~~~~~~^~~~
/usr/include/c++/9/bits/range_access.h:252:5: note: candidate: ‘template<class _Tp, long unsigned int _Nm> constexpr std::size_t std::size(const _Tp (&)[_Nm])’
  252 |     size(const _Tp (&/*__array*/)[_Nm]) noexcept
      |     ^~~~
/usr/include/c++/9/bits/range_access.h:252:5: note:   template argument deduction/substitution failed:

我不知道为什么会这样。任何帮助将不胜感激。

此外,我正在使用带有这些标志的 g++:

g++ -Wall -Weffc++ -Wextra -Wsign-conversion -Werror -std=c++17

首先,这个定义:

int components[]{};

完全错误。如果你真的需要旧的 c 风格数组,你需要使用 new:

来定义它们的大小
int *components = new int[size]; 

C 风格数组必须在编译期间知道它们的大小,除非您使用关键字 new。 如果您想使用未定义大小(可以修改)的集合,请阅读 std::vector。当你想找到它的大小时,使用这个调用:

int size_of_v = std::size(v);

第一个代码之所以有效,是因为一个事实——编译器可以判断数组有多大。

假设你只是想要一个答案,而且还想学习一些东西,这里是第一个代码的更“专业”版本:

#include <algorithm>
#include <array>
#include <iostream>

int main()
{
    std::array arr = {30, 50, 20, 10, 40};
    std::sort(begin(arr), end(arr));

    // modern old-fashioned loop, use it if you really need the index
    for (int i = 0; i < std::ssize(arr); ++i)
    {
        std::cout << arr[i] << '\t';
    }

    // better:
    for (auto elem : arr)
    {
        std::cout << elem << '\t';
    }

    std::cout << '\n';

    return 0;
}

解释:

  • 不需要使用 C 风格的数组,我使用 std::array 代替。请注意将它与初始化程序一起使用是多么容易:编译器会根据初始化程序
  • 自动提供 array 元素的类型和数量
  • 我更喜欢使用 = 语法初始化简单变量,而无需显式构造函数,例如 ints。您不必做同样的事情,但许多老朋友会因为您的惯例而分心。就像任何惯例一样,这是一个品味和双方同意的问题。
  • 因为我使用的是std::array,所以我不必在beginend之前加上std::,代码变得更简单
  • 在第一个循环中,我使用了 std::ssize,这是 C++20 中引入的一个特性,因此我不需要任何转换:代码再次得到简化
  • 但是,如果除了交互之外不需要索引,请选择基于范围的 for 循环,for (auto [const] [&] variable : container)
  • EXIT_SUCCESS0 更逐字(在 main 中都是多余的)
  • 旁注:一些程序员避免在流中使用字符文字,比如 ``\n\,因为他们害怕不小心写出像 ``\n\' or \'\n 这样的东西`',有意想不到的意义(自己试试吧!)。

现在,第二个错误代码。

它真正有趣的部分是:

int components[]{};  

在这里声明一个 C 风格的数组(现在您知道这通常不是最好的主意)components。根据标准,C 样式数组需要在编译时知道它们的大小,尽管许多编译器(如 gcc)具有使此要求无效的扩展。但这里不是这种情况,编译器拥有符合标准所需的所有信息:虽然您留下了空方括号,但您还提供了初始化列表。此列表为空。编译器得出结论,您的意图是这样的:

int components[0];  

你的数组有零元素,所以它不需要初始化器,实际上完全没用,不过,这是一个有趣的部分,你可以获取它的地址,在任何使用数组名/指针的表达式中使用它等价,将其用作 sizeof 等的参数。这就是问题的根源。