Wie Klassentyp von Methodentyp in C ++ Templates ableiten?
Frage
In Vorlagen wie unten dargestellt, würde ich der Anruf Run(&Base::foo)
ohne die Notwendigkeit gelingen mag zweimal den Basistyp zu nennen (wie in der Zusammenstellung Run<Base>(&Base::foo)
Anruf erfolgt). Kann ich das haben? Möglicherweise ohne Zugabe eine Tonne Boost- Header?
Mit dem bereitgestellten Code, erhalte ich einen Fehler von:
prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’
(Sie können mit dem Schnipsel Geige unter http://ideone.com/8NZkq ):
#include <iostream>
class Base {
public:
bool foo() { return true; }
};
Base* x;
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
T* y = dynamic_cast<T*>(x);
std::cout << (y->*check)();
}
int main() {
Base y;
x = &y;
Run<Base>(&Base::foo);
Run(&Base::foo); // why error?
}
Lösung
Die T
in Traits<T>::BoolMethodPtr
sind in einem nicht-abgeleitete Kontext, so dass der Compiler nicht deduce automatisch aus dem Aufruf, welche Art T sein sollte.
Dies liegt daran, da der Code wie folgt sein könnte:
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<>
struct Traits<int> {
typedef bool (Base::*BoolMethodPtr)();
};
Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */
Wenn Sie ohne die Traits<T>
Klasse tun können, können Sie schreiben Run
wie:
template<class Class>
void Run(bool (Class::*check)()) {
Class* y = dynamic_cast<Class*>(x);
std::cout << (y->*check)();
}
In diesem Zusammenhang kann Class
auf mittlere Base
abgeleitet werden
Andere Tipps
Um einen Typen auseinander zu nehmen, jede Art verwenden partielle Spezialisierung. Es gibt keine Funktion Schablonen-Teil Spezialisierung, so dass Sie direkt benötigen, um die Funktion auf ihrem Argument Typ parametrieren und den Klassentyp innerhalb abgerufen werden.
template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this
template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
typedef C host;
typedef void sfinae; // disallow function for non ptmf arguments
};
template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
typedef T BoolMethodPtr; // or something
typedef typename get_host_class< T >::host host;
}
Ich denke, das ein nicht davon abgeleitete Kontext ist.
14.8.2.5 $ / 5- „Die nicht-abgeleiteten Kontexten sind: - Die verschachtelten-name-Bezeichner eines Typ, der angegeben wurde unter Verwendung eines qualifizierte Nummer. "
Ich denke, das das Zitat, das in diesem Fall gilt. Aber einige Template Götter brauchen mein Verständnis zu ratifizieren.
Wenn der Compiler versucht, ein Template-Argument zu entsprechen, es hält nur der primäre Klassentyp. Mit anderen Worten, wenn er trifft den Ausdruck:
Run(&Base::foo);
... und es ist zu herauszufinden, die Template-Parameter für Run
versuchen, es hält nur die Art der foo
selbst und berücksichtigt nicht, was Klasse foo
ist ein Teil.
EDIT:
Und die Art der foo
ist bool(Base::*)(void)
, aber was Sie die Compiler wollen, ist zu finden nur Base