-3

This code below works as expected:

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

int main()
{
    int arr[] = {6, 4, 2};
    std::sort(std::begin(arr), std::end(arr));
    for (const auto &i : arr)
        std::cout << i << ' ';
    std::cout << std::endl;
}

Now consider what happens when we modify the code that doesn't do the sorting and printing:

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

int main()
{
    int n;
    std::cin >> n; // take n = 3
    int arr[n];
    for (int i = 0; i != n; ++i)
        std::cin >> arr[i]; // take (arr[0],arr[1],arr[2])=(6,4,2)

    std::sort(std::begin(arr), std::end(arr));
    for (const auto &i : arr)
        std::cout << i << ' ';
    std::cout << std::endl;
}

With gcc this results in the error (https://godbolt.org/z/W4av94TKj):

source>: In function 'int main()':
<source>:13:25: error: no matching function for call to 'begin(int [n])'
   13 |     std::sort(std::begin(arr), std::end(arr));
      |               ~~~~~~~~~~^~~~~
In file included from /opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/bits/range_access.h:36,
                 from /opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/string:51,
                 from /opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/ios:42,
                 from /opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/ostream:38,
                 from /opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/initializer_list:88:5: note: candidate: 'template<class _Tp> constexpr const _Tp* std::begin(initializer_list<_Tp>)'
   88 |     begin(initializer_list<_Tp> __ils) noexcept
      |     ^~~~~
/opt/compiler-explorer/gcc-trunk-20220623/include/c++/13.0.0/initializer_list:88:5: note:   template argument deduction/substitution failed:
<source>:13:25: note:   mismatched types 'std::initializer_list<_Tp>' and 'int*'
   13 |     std::sort(std::begin(arr), std::end(arr));
      |               ~~~~~~~~~~^~~~~
[... and a long list of more overloads ...]

Why is this an error? I know that the C++ standard requires the array size to be a constexpr. However, gcc does offer it as extensions that allow non-constexpr array sizes. But it doesn't answer the question of why the line that sorts the array is in error, and the rest isn't.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
Jangan
  • 5
  • 1
  • I don't think it is "most compilers". Anyhow, for compiler extensions you need to read the compilers manual. Which compiler do you use ? gcc ? – 463035818_is_not_an_ai Jun 23 '22 at 13:35
  • 2
    `std::cin >> n; int arr[n];` is not standard C++. If you compile with the `-pedantic-errors` flag then it will stop your compiler from excepting this non-standard code. – NathanOliver Jun 23 '22 at 13:35
  • @NathanOliver OP is aware that this is an extension. – Yksisarvinen Jun 23 '22 at 13:35
  • btw you read the size of the array from the user but then read 3 elements no matter what the actual size is – 463035818_is_not_an_ai Jun 23 '22 at 13:36
  • 1
    please update the question to include the compiler and the error message – 463035818_is_not_an_ai Jun 23 '22 at 13:36
  • if you write code that doesn't conform to the C++ standard you can't look to the standard to tell you what it does. Ask your compiler vendor. They're the ones who are causing this problem. – Pete Becker Jun 23 '22 at 13:37
  • @463035818_is_not_a_number "I don't think it is "most compilers"" It is. GCC, MSVC, Clang, etc – Jangan Jun 23 '22 at 13:39
  • ok then I have to check again. But we cannot answer "Why is there an error for this compiler specific extension" when you do not tell us the error nor what compiler you are using. – 463035818_is_not_an_ai Jun 23 '22 at 13:39
  • Well, saying why exactly is difficult without details about what compiler you're using and how it deals with VLAs, but a good guess is easy: the type of `arr` is not a sized array and there are no overloads of `std::begin` and `std::end` that take VLAs; the standard only gives overloads for sized arrays. I think implementations would be allowed to add overloads but I guess they don't. – HTNW Jun 23 '22 at 13:40
  • 1
    fwiw I did check again https://godbolt.org/z/E3KeEYT8G – 463035818_is_not_an_ai Jun 23 '22 at 13:41
  • 1
    @AnoopRana How does [Variable length arrays (VLA) in C and C++](https://stackoverflow.com/questions/14075194/variable-length-arrays-vla-in-c-and-c) or [Why aren't variable-length arrays part of the C++ standard?](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard) answer this question? Question whether VLAs are allowed in standard C++ is competely unrelated to this one. – Yksisarvinen Jun 23 '22 at 13:43
  • 1
    They aren't. I sacrificed my "debug info missing" vote for a reopen :/ – 463035818_is_not_an_ai Jun 23 '22 at 13:45
  • Just guessing here, but one way GCC (and others) may implement VLAs would be to do so by making those into pointers, which are then allocated with `new` or `malloc` calls. Such pointers aren't valid class types for `std::begin` and `std::end`. – Adrian Mole Jun 23 '22 at 13:46
  • 1
    @463035818_is_not_a_number Have one on me :) I agree this question can't be answered unless it asks about one specific VLA implementation (partly due to huge hate for them in C++ tag, and partly because it would be guess or opinion based anyway). – Yksisarvinen Jun 23 '22 at 13:48
  • FWIW, clang-cl (which supports VLAs under protest) gives this: *message : candidate template ignored: substitution failure: variably modified type 'int [n]' cannot be used as a template argument* on the `begin()` and `end()` calls. – Adrian Mole Jun 23 '22 at 13:52
  • 1
    Also, MSVC does **not** support VLAs in C++. IIRC, it also does not support them in C. – Adrian Mole Jun 23 '22 at 13:55
  • 1
    I think this could actually be an interesting question. I assumed you used gcc and added the missing details – 463035818_is_not_an_ai Jun 23 '22 at 14:03
  • I'm now *very* tempted to close this as a duplicate of [variable-sized array type int (size) is not a valid template argument](https://stackoverflow.com/q/46154120/10871073) ... but the (relevant) answer there is actually a comment (the second one from The Dude). – Adrian Mole Jun 23 '22 at 14:10
  • Why/who the -1? – Jangan Jun 23 '22 at 14:53
  • @AdrianMole Actually i already closed this question once with [this](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard) dupe. But then someone reopened it. I agree that the dupe [suggested by you](https://stackoverflow.com/q/46154120/10871073) is also related to this question and so this should be closed. Basically both of the dupes are related because the fundamental problem is the same in all the three questions(including this) which is that both a template parameter as well as the size of an array must be a compile time constant. – Jason Jun 23 '22 at 16:02
  • @Yksisarvinen The dupes are related to this question because the fundamental problem is the same which is that both a template parameter and the size of an array must be a compile time constant. – Jason Jun 23 '22 at 16:04
  • @AnoopRana In standard C++ yes. But we are discussing a specific compiler extension here. – Yksisarvinen Jun 23 '22 at 18:03

1 Answers1

4

The std::end overload for arrays is

template< class T, std::size_t N >
constexpr T* end( T (&array)[N] ) noexcept;

But

int n;
std::cin >> n; // take n = 3
int arr[n];

means that there is no compile time size to match the template argument. The STL function can not work on your VLA. You have to use

std::sort(arr, arr + n);
Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42