Es gab ein Problem: "schreiben Sie eine zweite Implementierung der Vorlagenfunktion", bei der dieselben Argumente übergeben werden. Das heißt, die Signatur beider Funktionen ist vollständig gleich. Der Unterschied besteht darin, dass std::vector-Container und std::map-Container als Funktionsargumente übergeben werden können. Und je nachdem, ob es sich um einen std::vector oder eine std::map handelt, sollte die eine oder andere Implementierung gewählt werden.
In diesem Fall wird die SFINAE-Regel verwendet, die besagt: Wenn die letzten Argumenttypen einer überladenen Template-Funktion nicht ausgewertet werden können (Substitution von Template-Parametern durchführen), wirft der Compiler keinen Fehler, sondern sucht nach einer anderen geeigneten Überladung. Der Fehler tritt in drei Fällen auf:
- Keine passende Überladung gefunden.
- Es wurden mehrere solcher Überladungen gefunden, und C++ kann sich nicht entscheiden, welche genommen werden soll.
- Es wurde eine Überladung erkannt, die sich als Vorlage herausstellte, und beim Instanziieren der Vorlage trat ein Fehler auf.
Unser Fall wird der zweite sein. Es gibt zwei Überladungsvorlagenfunktionen.
Implementierung
Um die erforderliche Überladung zu bestimmen, wird std::enable_if verwendet, das nur für solche Fälle verwendet wird, um eine bestimmte Funktion abhängig von der Art der zu verarbeitenden Daten zu spezialisieren.
Wie sich herausstellt, hat die Standardbibliothek STD keine Funktion, um festzustellen, ob ein Container eine std::map ist oder nicht. Aber auf StackOverflow wurde dieses Problem bereits diskutiert. Der dort angegebene Code muss nur ein wenig angepasst und korrekt angewendet werden, um die Spezialisierung von Funktionen je nach Containertyp zu schreiben.
Der Kern des Codes besteht darin, zur Kompilierzeit zu entscheiden, ob das Element des Containers ein std::pair ist, und basierend darauf zu entscheiden, ob der Container eine std::map ist. Wenn der Container std::map ist, wählen Sie eine Funktion aus; Wählen Sie andernfalls die zweite Implementierung der Funktion.
#include <iterator> #include <type_traits> // templates for determining whether the std::pair container element is template <typename T> struct is_pair : std::false_type {}; template <typename T, typename U> struct is_pair<std::pair<T, U>> : std::true_type {}; template <typename T> constexpr bool is_pair_v = is_pair<T>::value; // templates for determining if the container is std::map template<typename, typename = void> struct is_mapping : std::false_type {}; template <typename Container> struct is_mapping<Container, std::enable_if_t<is_pair_v<typename std::iterator_traits<typename Container::iterator>::value_type>>> : std::true_type {}; template <typename T> constexpr bool is_mapping_v = is_mapping<T>::value; #include <map> #include <vector> #include <iostream> class ClassWithSpecializedMethods { public: ClassWithSpecializedMethods() {} // A specialized method for handling std::map template <class ContainerType> static typename std::enable_if<is_mapping_v<ContainerType>, void>::type printContainer(ContainerType& container); // A specialized method for handling std::vector template <class ContainerType> static typename std::enable_if<!is_mapping_v<ContainerType>, void>::type printContainer(ContainerType& container); }; // Method implementations template <class ContainerType> inline static typename std::enable_if<is_mapping_v<ContainerType>, void>::type ClassWithSpecializedMethods::printContainer(ContainerType& container) { std::cout << "Map:" << std::endl; for (const auto& [key, value] : container) { std::cout << "Key: " << key << " Value: " << value << std::endl; } std::cout << std::endl; } template <class ContainerType> inline static typename std::enable_if<!is_mapping_v<ContainerType>, void>::type ClassWithSpecializedMethods::printContainer(ContainerType& container) { std::cout << "Vector:" << std::endl; for (const auto& value : container) { std::cout << "Value: " << value << std::endl; } std::cout << std::endl; } // Testing functions int main() { std::cout << "is_pair:" << std::endl; std::cout << "Map: " << is_pair_v<std::iterator_traits<std::map<int, int>::iterator>::value_type> << std::endl; std::cout << "Vector: " << is_pair_v<std::iterator_traits<std::vector<int>::iterator>::value_type> << std::endl; std::cout << std::endl; std::cout << "is_mapping:" << std::endl; std::cout << "Map: " << is_mapping_v<std::map<int, int>> << std::endl; std::cout << "Vector: " << is_mapping_v<std::vector<int>> << std::endl; std::cout << std::endl; std::map<int, int> map_container = {{1, 1}, {2, 2}, {3, 3}}; std::vector<int> vector_container = {1, 2, 3}; ClassWithSpecializedMethods::printContainer(map_container); ClassWithSpecializedMethods::printContainer(vector_container); }
C++-Standards verwendet
Damit dieser Code funktioniert, müssen Sie den C++17-Standard verwenden; Auf einem kleineren Standard wird der Code nicht kompiliert.
In QMake-Projekten sollten die folgenden Zeilen zur Profildatei hinzugefügt werden
CONFIG += console c++17 QMAKE_CXXFLA ## Conclusion As a conclusion, we get the following conclusion ```lang-bsh ist_paar: Karte: 1 Vektor: 0 is_mapping: Karte: 1 Vektor: 0 Karte: Schlüssel: 1 Wert: 1 Schlüssel: 2 Wert: 2 Schlüssel: 3 Wert: 3 Vektor: Wert: 1 Wert: 2 Wert: 3