Załóżmy, że otrzymuję dwa argumenty do szablonu, T1 i T2. Jeśli wiem, że T1 jest samą klasą szablonową (np. Kontenerem), a T2 może być cokolwiek, czy jest możliwe dla mnie określenie podstawowego typu szablonu dla T1 i przebudowanie go za pomocą T2 jako jego argumentu?Czy można rozplątać szablon z jego argumentów w C++?
Na przykład, jeśli otrzymam std::vector<int>
i std::string
, będę chciał automatycznie zbudować std::vector<std::string>
. Jednakże, gdybym otrzymał std::set<bool>
i double
, to by wyprodukować std::set<double>
.
Po przejrzeniu typ_traits, odpowiednich blogów i innych pytań tutaj, nie widzę ogólnego podejścia do rozwiązania tego problemu. Jedynym sposobem, jaki mogę obecnie zobaczyć, aby wykonać to zadanie, jest zbudowanie adapterów szablonów dla każdego typu, które można przekazać jako T1.
Na przykład, gdybym miał:
template<typename T_inner, typename T_new>
std::list<T_new> AdaptTemplate(std::list<T_inner>, T_new);
template<typename T_inner, typename T_new>
std::set<T_new> AdaptTemplate(std::set<T_inner>, T_new);
template<typename T_inner, typename T_new>
std::vector<T_new> AdaptTemplate(std::vector<T_inner>, T_new);
powinienem móc korzystać decltype i polegać na operatora przeciążenia, aby rozwiązać mój problem. Coś na wzór:
template <typename T1, typename T2>
void MyTemplatedFunction() {
using my_type = decltype(AdaptTemplate(T1(),T2()));
}
Czy czegoś brakuje? Czy istnieje lepsze podejście?
DLACZEGO chcę to zrobić?
Buduję bibliotekę C++, w której chcę uprościć to, co użytkownicy muszą zrobić, aby zbudować modułowy szablon. Na przykład, jeśli użytkownik chce zbudować symulację opartą na agentach, może skonfigurować szablon World z typem organizmu, menedżerem populacji, menedżerem środowiska i menedżerem systematyki.
Każdy z menedżerów również wiedzieć, rodzaj organizmu, więc deklaracja może wyglądać mniej więcej tak:
World< NeuralNetworkAgent, EAPop<NeuralNetworkAgent>,
MazeEnvironment<NeuralNetworkAgent>,
LineageTracker<NeuralNetworkAgent> > world;
Wolałbym użytkownicy nie muszą powtarzać NeuralNetworkAgent
każdym razem. Jeśli jestem w stanie zmienić argumenty szablonu, a następnie domyślne argumenty mogą być używane, a powyżej można uprościć do:
World< NeuralNetworkAgent, EAPop<>, MazeEnvironment<>, LineageTracker<> > world;
Plus to łatwiejsze do konwersji z jednego typu do innego świata, nie martwiąc się o błędy typu.
Oczywiście, mogę poradzić sobie z większością błędów za pomocą static_assert i po prostu radzić sobie z dłuższymi deklaracjami, ale chciałbym wiedzieć, czy lepsze rozwiązanie jest możliwe.
Wszystkie trzy odpowiedzi dostałem były doskonałe. Ten przez @Barry jest najbardziej dokładny i jeden przez T.C. najlepiej rozwiązuje mój podstawowy problem, ale myślę, że odpowiedź Sama Varshavchika (którą zaakceptowałem) jest najbardziej elegancka, jeśli chodzi o rozwiązanie tego pytania. Bardzo wam wszystkim dziękuję! –
Co do tego, że ten post jest duplikatem, uważam, że ten, który został wskazany przez @Ben Voight, jest bardzo podobny, ale koncentruje się w szczególności na STL. Jeśli wszystkie omawiane szablony pochodzą z tej samej biblioteki, są z pewnością dodatkowe sztuczki, które mogą być możliwe. To powiedziawszy, inne pytanie ma również kilka interesujących i użytecznych odpowiedzi. To powiedziawszy, uważam, że udzielone tutaj odpowiedzi są bardziej ukierunkowane na to pytanie i są bardziej przydatne. –
Chociaż inne pytanie jest mniej obszerne, odpowiedzi całkowicie pokrywają twoją sprawę. Dlatego moja flaga skutkuje banerem z napisem "Twoje pytanie ma już tutaj odpowiedź". –