Mam funkcję, która przyjmuje wielowymiarowość std::vector
i wymaga podania głębokości (lub liczby wymiarów) jako parametru szablonu. Zamiast na stałe wpisywać tę wartość, chciałbym napisać constexpr
funkcję, która pobierze std::vector
i zwróci głębokość jako unsigned integer
wartość.
Na przykład:
std::vector<std::vector<std::vector<int>>> v =
{
{ { 0, 1}, { 2, 3 } },
{ { 4, 5}, { 6, 7 } },
};
// Returns 3
size_t depth = GetDepth(v);
Należy to zrobić w czasie kompilacji, ponieważ ta głębokość zostanie przekazana do funkcji szablonu jako parametr szablonu:
// Same as calling foo<3>(v);
foo<GetDepth(v)>(v);
Czy jest na to sposób?
std::vector
jest kwestią czasu wykonywania, a nie kompilacji. Jeśli potrzebujesz kontenera w czasie kompilacji, spójrz nastd::array
. Również; pamiętaj, żeconstexpr
oznacza to tylko „ można ocenić w czasie kompilacji” - nie ma obietnicy, że tak będzie . Można to ocenić w czasie wykonywania.std::vector
s są w sobie zagnieżdżone. Na przykładstd::vector<std::vector<int>> v;
,GetDepth(v);
zwróci 2, ponieważ jest to wektor dwuwymiarowy. Rozmiar nie ma znaczenia.vector
nie zawsze jest najlepszym sposobem na robienie rzeczy. Ręczne indeksowanie 2d lub 3d pojedynczego płaskiego wektora może być bardziej wydajne, w zależności od przypadku użycia. (Tylko matematyka całkowita zamiast gonić za wskazówkami z zewnętrznych poziomów.)rank
tego zapytania do typów tablic (zgodnie z nomenklaturą matematyczną dla tensorów). Być może jest to lepsze słowo niż „głębia”.Odpowiedzi:
Klasyczny problem szablonów. Oto proste rozwiązanie, takie jak standardowa biblioteka C ++. Podstawową ideą jest posiadanie szablonu rekurencyjnego, który będzie zliczał jeden po drugim dla każdego wymiaru, z podstawowym przypadkiem 0 dla każdego typu, który nie jest wektorem.
Więc możesz użyć go w następujący sposób:
Edytować:
Ok, zakończyłem ogólną implementację dowolnego typu kontenera. Zauważ, że zdefiniowałem typ kontenera jako dowolny element, który ma dobrze uformowany typ iteratora zgodnie z wyrażeniem, w
begin(t)
którymstd::begin
jest importowany do wyszukiwania ADL it
jest wartością typuT
.Oto mój kod wraz z komentarzami wyjaśniającymi, dlaczego działają rzeczy i przypadki testowe, których użyłem. Uwaga, wymaga to kompilacji C ++ 17.
źródło
std::vector<T>
specjalizację i zmienić ją na inny typ kontenera. Jedyne, czego potrzebujesz, to skrzynka podstawowa 0 dla każdego typu, dla którego się nie specjalizujeszZakładając, że kontener jest dowolnego typu
value_type
i maiterator
typy elementów (standardowe kontenery biblioteczne spełniają to wymaganie) lub tablicę w stylu C, możemy łatwo uogólnić rozwiązanie Cruz Jean :W razie potrzeby typy kontenerów można dodatkowo ograniczyć.
źródło
Możesz zdefiniować następujący szablon klasy,
vector_depth<>
który pasuje do dowolnego typu:Ten podstawowy szablon odpowiada przypadkowi bazowemu, który kończy rekurencję. Następnie zdefiniuj odpowiednią specjalizację dla
std::vector<T>
:Ta specjalizacja pasuje do
std::vector<T>
i odpowiada przypadkowi rekurencyjnemu.Na koniec zdefiniuj szablon funkcji
GetDepth()
, który odwołuje się do szablonu klasy powyżej:Przykład:
Dane wyjściowe tego programu to:
źródło
std::vector
, ale na przykładGetDepth(v)
, gdziev
jestint
nie skompiluje. Lepiej byłoby miećGetDepth(const volatile T&)
i po prostu wrócićvector_depth<T>::value
.volatile
po prostu pozwala na pokrycie większej liczby rzeczy, mając maksymalną kwalifikację cv