1

I've been trying to start using std::span<const T> in places where I would have previously used const std::vector<T>&. The only sticking point I have is illustrated in the following:

#include <iostream>
#include <vector>
#include <span>
#include <numeric>

double mean1(std::span<const double> vals) {
    return std::accumulate(vals.begin(), vals.end(), 0.0) / vals.size();
}

double mean2(const std::vector<double>& vals) {
    return std::accumulate(vals.begin(), vals.end(), 0.0) / vals.size();
}


int main() {
    std::vector<double> foo = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
    auto v = mean1(foo);
    std::cout << v << "\n";

    v = mean2( { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 } );
    std::cout << v << "\n";

    v = mean1({ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 } ); // << this is an error
    std::cout << v << "\n";

}

I know that passing std:vector{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 } would work but that is pretty verbose. initializer_list is even more verbose. Just wondering if I am missing something obvious here.

The specific error from Visual Studio is

C2664 'double mean1(std::span<const double,18446744073709551615>)': cannot convert argument 1 from 'initializer list' to 'std::span<const double,18446744073709551615>'

I think, basically, std::span doesn't have a constructor that takes an initializer list.

jwezorek
  • 8,592
  • 1
  • 29
  • 46
  • 1
    If you get errors, *what* errors do you get? Please [edit] your question to show the full and complete build log. – Some programmer dude Sep 12 '22 at 17:32
  • What's really wrong with an rvalue std::vector like `vector {1.0, 2.0, ...}`?? You can avoid typing `std::` by having this statement `using std::vector;` in your main function. – digito_evo Sep 12 '22 at 17:34

1 Answers1

2

you can use

mean1( {{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }} );

which invoke the raw array constructor.


if you want to specify the type, I'd suggest

mean1( std::initializer_list{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 } )

which prevent the potential construction of another container. (which still construct a initializer_list anyway)

apple apple
  • 10,292
  • 2
  • 16
  • 36
  • the double curly brace thing is perfect but I am not sure I understand why it works ... is it special syntax for defining an std::array or what? – jwezorek Sep 12 '22 at 19:18
  • @jwezorek it means something like `mean1(std::span{const double[]{ 1.0, 2.0, 6.0, 4.0, 5.0, 6.0 }} );` – apple apple Sep 12 '22 at 19:26
  • @jwezorek it work for array, `void x(const int(&)[N]);` can be called with `x({1,2,3})` – apple apple Sep 12 '22 at 19:38
  • I guess my confusion is that if `mean1( {{1.0,2.0,3.0}} )` means `mean1( span{ double(&)[N]{1.0,2.0,3.0}} )` in this context, why would it not mean `mean1( span{ initializer_list{1.0,2.0,3.0}} )` and fail with the same error message as in the question? – jwezorek Sep 12 '22 at 21:27
  • 1
    @jwezorek because `braced-init-list` is not `std::initialier_list`, and since span constructor doesn't accept `std::initilizer_list`, there is no reason compiler convert to it. (See the conditions here: https://en.cppreference.com/w/cpp/utility/initializer_list) – apple apple Sep 13 '22 at 08:30