1

It appears that std::span<T,Extent>::subspan has two overloads.

Here (live):

#include <array>
#include <span>
#include <fmt/core.h>


void show_sizes( const std::span<const char* const> command_line_arguments )
{
    fmt::print( "{}\n", command_line_arguments.size( ) );

    const auto command_line_options { command_line_arguments.subspan( 1 ) }; // this
    const auto command_line_options { command_line_arguments.subspan<1>( ) }; // or this?

    fmt::print( "{}\n", command_line_options.size( ) );
}

int main( int argc, char* argv[] )
{
    const std::span<const char* const> command_line_arguments { argv, static_cast<std::size_t>( argc ) };
    show_sizes( command_line_arguments );
}

Which one is better for the above case (since we already know that argc can't be less than 1 so there's probably no chance for UB)?

What is really the purpose of the overload that takes no arguments? Is it there for better compile-time evaluation? What is the advantage?

digito_evo
  • 3,216
  • 2
  • 14
  • 42
  • "_since we already know that argc can't be less than 1_": That's incorrect. `argc` is allowed to be `0` in general per C and C++ standards and also POSIX, although some OS (including very recent Linux versions) make sure that it won't happen. So there is potential for UB either way. – user17732522 May 02 '23 at 15:43
  • @user17732522 How can I prevent UB then? – digito_evo May 02 '23 at 16:22
  • 1
    By adding a check that `argc` is not `0` or that the original span does not have size `0` before taking the subspan. – user17732522 May 02 '23 at 16:24
  • @user17732522 Right. I guess I prefer to check the size of the original span. – digito_evo May 02 '23 at 16:26
  • @user17732522 What do you think is appropriate as an error code for such a failure (i.e. when `argc == 0` and the program returns with exit code 1)? I have a function that handles the startup-related errors and returns a `std::error_condition` but I could not find a meaningful [`std::errc`](https://en.cppreference.com/w/cpp/error/errc) value for this particular error. – digito_evo May 02 '23 at 21:39
  • I don't know what code is appropriate, but it should probably not be an error. Most normal programs do not need the zeroth argument and should just work if none is specified the same way as if only one argument was specified. – user17732522 May 03 '23 at 21:03
  • @user17732522 Hmm. Makes sense. So I think I should make the startup function return an empty error condition indicating a successful startup. – digito_evo May 03 '23 at 21:18

1 Answers1

2

The first overload is for fixed-size spans if their extent can be known statically. For example:

// A `std::span<T, 3>` of the last 3 elements
std::span<T, 5>{...}.subspan<2>();

// A `std::span<T, 5>` of the first 5 elements after skipping the first
std::span<T>{...}.subspan<1, 5>();

For std::span<T>{...}.subspan<N>() vs std::span<T>{}.subspan(N), there is no difference in behaviour since the size is still not known.

Artyer
  • 31,034
  • 3
  • 47
  • 75
  • Which one should be preferred then? – digito_evo May 02 '23 at 16:24
  • 1
    @digito_evo Purely a matter of opinion. If you don't use static extent spans, I would personally go for `subspan( 1 )`. – Artyer May 02 '23 at 16:29
  • Your last sentence doesn't make sense? At compile time, arguments to templates are known, so I'm not sure what you mean. – Yakk - Adam Nevraumont May 02 '23 at 20:07
  • @Yakk-AdamNevraumont If the size of a `std::span` is `n` (not in the type since it has dynamic extent), `std::span::subspan()` will have size `n - Offset`, still not known, leading to another span with dynamic extent – Artyer May 02 '23 at 20:36