Why can't I build gsl :: span with a list of initializers enclosed in parentheses

According to C ++ Fundamentals , I have to use gsl :: span to go through a semi-open sequence .

I think this means that instead of writing a function like:

void func(const std::vector<int>& data) { for (auto v : data) std::cout << v << " "; } 

I should prefer:

 void func(gsl::span<const int> data) { for (auto v : data) std::cout << v << " "; } 

Which has the advantage that it does not assume that the caller has his data in vector or forces them to create a temporary vector . They could pass std::array , for example.

But a common use case is to pass a list of initializers enclosed in parentheses:

 func({0,1,2,3}) 

This works for a function with std::vector , but for a function that accepts gsl::span , I get an error:

error C2664: 'void func (gsl :: span)': cannot convert argument 1 from 'initializer-list' to 'gsl :: span'

It seems that gsl::span has a template constructor designed to capture any container.

Is it just something missing from the Microsoft GSL implementation, or is there a good reason to prevent this practice?

+5
source share
2 answers

When you call the vector version, the initializer list is used to create a temporary std::vector , which is then passed to the function via the const reference. This is possible because std::vector has a constructor that takes std::initializer_list<T> as an argument.
However, gsl::span does not have such a constructor, and {1,2,3} does not have a type, nor can it be accepted by the template constructor you mentioned (except that std::initializer_list<T> not satisfied with the container concept anyway).

One (ugly) workaround would, of course, be to explicitly create a temporary array:

 func(std::array<int,3>{ 0,1,2,3 }); 

I don’t see any special reason why gsl::span should not have a constructor that accepts std::initializer_list , but keep in mind that this library is still quite new and is under active development. So, perhaps, this is what they lose sight of, did not have time to implement, were not sure how to act correctly or there are some details that would make this design dangerous. It is probably best to ask the developers directly on github.


EDIT:
As @Nicol Bolas explains in his comment, this was by design because a list of initializers, such as {0,1,2,3} (and elements inside), is a temporary object and since gsl::span not its own container ( he does not accept ownership of the elements), they think it would be too easy to accidentally create a gsl::span that contains a dangling link to these temporary elements.

So for now, everything will be fine:

 func({ 0,1,2,3 }); 

because the lifetime of the initializer list ends after the function finishes, something like this would create a dangling link:

 gsl::span<const int> data{ 0,1,2,3 }; func(data); 
+8
source

Span does not own. Does not own the repository. This is a replacement for pointer arithmetic, not storage class.

You need to put your data in a storage class, and then if you want to do smart things using pointer arithmetic, you do smart things at intervals instead.

You cannot initialize a range with a list of initializers, because there is nowhere for data.

+1
source

Source: https://habr.com/ru/post/1236630/


All Articles