2015-11-23 14 views
5

Zgodnie z , powinienem use a gsl::span to pass a half-open sequence.Dlaczego nie mogę skonstruować gsl :: span z listwą inicjalizacyjną z nawiasami klamrowymi

myślę, że oznacza to, że zamiast pisać funkcji jak:

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

Wolałbym:

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

który ma tę zaletę, że nie ponosi dzwoniący ma swoje dane w vector lub zmusić ich do skonstruowania tymczasowego vector. Mogliby na przykład podać std::array.

Ale częstym use-case jest przekazać listę initializer Brace-ogrodzony:

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

To działa dla funkcji podjęciem std::vector ale dla funkcji podjęciem gsl::span otrzymuję komunikat o błędzie:

error C2664: 'void func (GSL :: rozpiętość)': nie można przekonwertować argumentu 1 z 'inicjatora liście' do 'GSL :: rozpiętości'

Wygląda na to, że jest przeznaczony do pobierania dowolnego kontenera.

Czy czegoś takiego brakuje w implementacji Microsoft GSL, czy też istnieje dobry powód, aby temu zapobiec?

+1

Lista usztywniona nie jest pojemnikiem. –

+0

@KerrekSB Czy 'std :: initializer_list' jest kontenerem? – user3467895

+2

Nie, nie jest. Jest to typ obsługi języka, który reprezentuje listy inicjalizatorów ... Ale nawet gdyby to było, to by nie pomogło, ponieważ twój argument nie jest typu 'std :: initializer_list '. To tylko usztywniona lista. –

Odpowiedz

8

Po wywołaniu wersji wektorowej lista inicjalizacyjna jest używana do utworzenia tymczasowego std::vector, która jest następnie przekazywana do funkcji przez odniesienie do stałej. Jest to możliwe, ponieważ std::vector ma konstruktora, który przyjmuje std::initializer_list<T> jako argument.
Jednak gsl::span nie ma takiego konstruktora, a jako {1,2,3} nie ma typu, nie może być również zaakceptowany przez wspomnianego konstruktora szablonowego (poza faktem, że i tak std::initializer_list<T> nie spełniałoby koncepcji pojemnika).

One (brzydki) Rozwiązaniem byłoby oczywiście jawnie utworzyć tymczasowy tablicy:

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

ja nie widzę szczególnego powodu, dlaczego nie powinno mieć gsl::span konstruktor, że trwa std::initializer_list, ale zachować pamiętać, że ta biblioteka jest wciąż całkiem nowa i znajduje się pod aktywnym rozwojem. Być może jest to coś, co przeoczyli, nie mieli czasu na wdrożenie, nie byli pewni, jak to zrobić właściwie lub są naprawdę pewne szczegóły, które sprawiają, że ta konstrukcja jest niebezpieczna. Najlepiej jest zapytać programistów bezpośrednio na github.


EDIT:
Jak @Nicol Bolas wyjaśnia w swoim komentarzu, to był by design ponieważ lista inicjator jak {0,1,2,3} (a elementy wewnątrz) to tymczasowy obiekt i jak gsl::span nie jest kontenerem w sobie (nie bierze własności elementów), uważają, że zbyt łatwo byłoby przypadkowo utworzyć gsl::span, która zawiera zwisające odniesienie do tych tymczasowych elementów.

Tak więc, choć to byłoby OK:

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

ponieważ żywotność listy inicjatora kończy się po zakończeniu funkcji, coś takiego byłoby stworzyć dangling odniesienia:

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

@NicolBolas: Dziękuję, dodałem to do mojej odpowiedzi. Może możesz sprawdzić, czy edycja jest poprawna. – MikeMB

+0

Tak, to podstawowy pomysł. –

1

Span nie jest właścicielem. Nie ma własnego magazynu. Jest zamiennikiem arytmetyki wskaźnika, a nie klasy pamięci.

Musisz umieścić swoje dane w klasie pamięci, a następnie, jeśli chcesz robić sprytne rzeczy za pomocą arytmetyki wskaźników, zamiast tego rób sprytne rzeczy.

Nie można zainicjować zakresu z listą inicjalizatora, ponieważ nie ma miejsca na umieszczenie danych.

Powiązane problemy