variadic template - Elemente einen vector hinzufügen
-
Gibt es eine Möglichkeit alle Elemente hinzuzufügen ohne einen Kontainer zu erstellen?
#include <iostream> #include <vector> #include <array> template<typename T, typename... Args> void addAll(std::vector<T>& vec, Args... args) { std::array<T, sizeof...(args)> array = { args... }; for (const auto& i : array) { vec.push_back(i); } } int main() { std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; addAll(vec, 10, 11, 12, 13, 14, 15); for (const auto& i : vec) { std::cout << i << "\n"; } std::getchar(); }
-
Ja - Indem du die Funktion rekursiv aufrufst. Um die Rekursion zu stoppen brauchst du einen Rekursionsanker.
template<typename T> void f(std::vector<T>& ) {} // Rekursionsanker - Wenn arguments... ins Nichts expandiert template<typename T, typename Head, typename... Args> void f(std::vector<T>& container, Head&& head, Args&&... arguments){ container.push_back(std::forward<Head>(head)); f(container, std::forward<Args>(arguments)...); // head wurde hinzugefügt - fahre fort mit den restlichen Argumenten }
-
struct sequential_exec { template <typename... T> constexpr sequential_exec(T&&...) noexcept {} }; template<typename T, typename... Args> void addAll(std::vector<T>& vec, Args&&... args) { // emplace_back gibt eine Referenz zurück, damit erübrigt sich der Kommaoperatorhack sequential_exec{ vec.emplace_back( std::forward<Args>( args ) )... }; }und in C++17 dann zu
template<typename T, typename... Args> void addAll(std::vector<T>& vec, Args&&... args) { ( vec.push_back( std::forward<Args>( args ) ), ... ); }
-
Ist das mit dem Rekursionsanker eigentlich weniger effizienter, als das andere? Oder tut das hier nicht zur Sache?
Ich weiß jetzt nicht, wie ich ASM Code dazu ansehen kann.
-
vnoob schrieb:
Ist das mit dem Rekursionsanker eigentlich weniger effizienter, als das andere?
Theoretisch nicht. Die Ausdrücke, die Nebeneffekte erzeugen, sind schließlich die Gleichen.
Praktisch wäre es denkbar, das der Compiler ab einer gewissen Rekursionstiefe das Inlining aufgibt, was sich ggf. (sehr geringfügig) negativ auswirken könnte.
-
camper schrieb:
struct sequential_exec { template <typename... T> constexpr sequential_exec(T&&...) noexcept {} }; template<typename T, typename... Args> void addAll(std::vector<T>& vec, Args&&... args) { // emplace_back gibt eine Referenz zurück, damit erübrigt sich der Kommaoperatorhack sequential_exec{ vec.emplace_back( std::forward<Args>( args ) )... }; }Das geht so nicht in C++14. In C++14 ist emplace_back void, eine Referenz wird erst in C++17 zurückgegeben. Der ansckließende pack fold Ausdruck für C++17 ist ok.
-
Ah, stimmt. Das passiert, wenn man nur in den letzten Draft schaut.
Also so in C++11 und C++14:template<typename T, typename... Args> void addAll(std::vector<T>& vec, Args&&... args) { sequential_exec{ ( vec.push_back( std::forward<Args>( args ) ), 0 )... }; }