Basierend auf an answer from Nawaz Ich möchte enable_if verwenden, um festzustellen, ob ein Vorlageargument ein Container ist oder nicht, und wenn es ist, möchte ich stattdessen eine benutzerdefinierte Nachricht für den Typnamen anzeigen des Namens von der Typid. Ich habe die Template-Spezialisierung auf zwei Arten implementiert. Der Code kompiliert und läuft, aber in keinem Fall wird die spezialisierte Methode aufgerufen. Ich nehme an, ich benutze enable_if falsch, was ist die richtige Anwendung hier?Std :: enable_if auf einem Vorlageargument zum Ermitteln des STL-Containers
Ich legte eine in sich geschlossene kleine Konsole Anwendung unter der Sequenz in dem Code ist: (a) erforderlichen Include-Dateien (b) die vorbereitende Vorlage Code (mit SFINAE) (c) zwei Implementierungen der Struktur, die angenommen werden die Aufgabe, (d) eine Client-Code
#include <typeinfo>
#include <string>
#include <list>
#include <vector>
#include <iostream>
using namespace std;
template<typename T>
struct has_const_iterator
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::const_iterator*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
typedef T type;
};
template <typename T>
struct has_begin_end
{
template<typename C> static char(&f(typename std::enable_if<
std::is_same<static_cast<typename C::const_iterator(C::*)() const>(&C::begin),
typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
template<typename C> static char(&f(...))[2];
template<typename C> static char(&g(typename std::enable_if<
std::is_same<static_cast<typename C::const_iterator(C::*)() const>(&C::end),
typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
template<typename C> static char(&g(...))[2];
static bool const beg_value = sizeof(f<T>(0)) == 1;
static bool const end_value = sizeof(g<T>(0)) == 1;
};
template<typename T>
struct is_container : std::integral_constant<bool,
has_const_iterator<T>::value &&
has_begin_end<T>::beg_value &&
has_begin_end<T>::end_value>
{ };
struct TypeName {
template <typename T>
static const char* get() {
return typeid(T).name();
}
template <typename T, typename std::enable_if<is_container<T>::value>::type >
static const char* get()
{
typedef typename T::value_type ElementType;
std:string containerType = "";
if (std::is_same<decltype(std::vector<ElementType>), T>::value) {
containerType = "(Vector) ";
}
if (std::is_same<decltype(std::list<ElementType>), T>::value) {
containerType = "(List) ";
}
std::string returnString = "Container " + containerType;
returnString += " of ";
returnString += get<ElementType>();
return returnString.c_str();
}
};
template <typename T> struct GypeName {
static const char* get() {
return typeid(T).name();
}
template <class = typename std::enable_if<is_container<T>::value>::type >
static const char* get()
{
typedef typename T::value_type ElementType;
std:string containerType = "";
if (std::is_same<decltype(std::vector<ElementType>), T>::value) {
containerType = "(Vector) ";
}
if (std::is_same<decltype(std::list<ElementType>), T>::value) {
containerType = "(List) ";
}
std::string returnString = "Container " + containerType;
returnString += " of ";
returnString += GypeName<ElementType>::get();
return returnString.c_str();
}
};
int main(int argc, char** argv) {
cout << is_container<int>::value << endl;
cout << is_container<std::vector<int>>::value << endl;
cout << TypeName::get<int>() << endl;
cout << TypeName::get<std::string>() << endl;
cout << TypeName::get<std::vector<int>>() << endl;
cout << TypeName::get<std::vector<std::vector<int>>>() << endl;
cout << GypeName<int>::get() << endl;
cout << GypeName<std::string>::get() << endl;
cout << GypeName<std::vector<int>>::get() << endl;
cout << GypeName<std::vector<std::vector<int>>>::get() << endl;
return 0;
}
der Ausgang des ganzen ist
0
1
int
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
class std::vector<int,class std::allocator<int> >
class std::vector<class std::vector<int,class std::allocator<int> >,class std::allocator<class std::vector<int,class std::allocator<int> > > >
int
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
class std::vector<int,class std::allocator<int> >
class std::vector<class std::vector<int,class std::allocator<int> >,class std::allocator<class std::vector<int,class std::allocator<int> > > >
Nicht Aufruf der Spezialfunktion in jedem Fall auszuführen.
Es gibt Tippfehler/Compiler-Fehler in bereitgestellten Code, [Demo ] (http://coliru.stacked-crooked.com/a/774f27cddb6363be) einmal behoben, (aber UB nicht behoben (Rückgabe const Char * von temporär)). – Jarod42
Der Code erfordert Boost und verwendet C++ 11 (Visual Studio 2015) - Ich werde die Referenz entfernen und etwas in sich geschlossen geben .. –
OK, Hauptproblem war enable_if sollte auf der Rückgabetyp nicht die Vorlage Argumente sein. Danke Jarod42. –