Reputation: 13
I am working with arrays. So to find size of array, I need to use std::size(), it works well in one program but fails to work in another.
The program that works:
#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;
}
Output:
10 20 30 40 50
The program that doesn't work:
#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;
}
It gives a compiler error as follows:
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:
I have no clue why would that happen. Any help would be appreciated.
Also, I am using g++ with these flags:
g++ -Wall -Weffc++ -Wextra -Wsign-conversion -Werror -std=c++17
Upvotes: 1
Views: 1740
Reputation: 2860
Assuming that you nit only want an answer, but also to learn something, here's a bit more "professional" version of the first code:
#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;
}
Explanation:
std::array
instead. Please notice how easy it is to use it with an initializer: the compiler automatically supplies the type and the number of array
elements based on the initializerint
s, using the =
syntax. You don't have to do the same, but many old-timers will be a bit distracted by your convention. Just as with any convention, its a matter of taste and mutual agreement.std::array
, I don't have to precede begin
and end
with std::
, and the code gets simplerstd::ssize
, a feature introduced in C++20, so I don't need any casts: the code gets simplified againfor
loops, for (auto [const] [&] variable : container)
EXIT_SUCCESS
is more verbatim than 0
(both are redundant in main
)\
, with streams because they're afraid of writing by accident something like `` \n\' or \'
\n `', which has an unexpected meaning (try it yourself!).Now, the second, erroneous code.
Its really interesting part is this:
int components[]{};
Here you declare a C-style array (now you know it is usually not the best idea) components
. According to the standard, C-style arrays need their size to be known at compile time, though many compilers, like gcc, have extensions that kind of invalidates this requirement. But this is not the case here, the compiler has all the information it needs to be standard conformant: although you left the empty square brackets, you also provided the initialization list. This list is empty. The compiler concludes that your intention was this:
int components[0];
Your array has zero-elements, so it does not need an initializer and actually is completely useless, although, here's an interesting part, you can take its address, use it in any expression utilizing the array-name / pointer equivalence, use it as the argument of sizeof
etc. This is the source of your problem.
Upvotes: 0
Reputation: 721
First of all, this definition :
int components[]{};
Is completely wrong. If you really needed to you old c-style arrays, you need to define their size using new:
int *components = new int[size];
C-style arrays have to know their size during compilation, unless you use keyword new.
If you want to use collection with undefined size ( that can be modified), read about std::vector
. When you want o find its size, use this call:
int size_of_v = std::size(v);
First code works only because of one fact - compiler can tell how big array is.
Upvotes: 6