Wie kann ich erzwingen, dass ein Vorlagenparameter Teine Unterklasse einer bestimmten Klasse ist Baseclass? Etwas wie das:
template <class T : Baseclass> void function(){
T *object = new T();
}
Wie kann ich erzwingen, dass ein Vorlagenparameter Teine Unterklasse einer bestimmten Klasse ist Baseclass? Etwas wie das:
template <class T : Baseclass> void function(){
T *object = new T();
}
Tabgeleitet Baseclass. Ab sofort ist diese Überprüfung implizit und für die Überlastungsauflösung nicht sichtbar. Wenn jedoch nirgends eine solche implizite Einschränkung vorgenommen wird, scheint es keinen Grund für eine künstliche Einschränkung zu geben.
Antworten:
In diesem Fall können Sie Folgendes tun:
template <class T> void function(){
Baseclass *object = new T();
}
Dies wird nicht kompilieren , wenn T nicht eine Unterklasse von Basisklasse (oder T ist Basisklasse).
Mit einem C ++ 11-kompatiblen Compiler können Sie Folgendes tun:
template<class Derived> class MyClass {
MyClass() {
// Compile-time sanity check
static_assert(std::is_base_of<BaseClass, Derived>::value, "Derived not derived from BaseClass");
// Do other construction related stuff...
...
}
}
Ich habe dies mit dem Compiler gcc 4.8.1 in einer CYGWIN-Umgebung getestet - daher sollte es auch in * nix-Umgebungen funktionieren.
template<class TEntity> class BaseBiz { static_assert(std::is_base_of<BaseEntity, TEntity>::value, "TEntity not derived from BaseEntity");...
Informationen zur Ausführung von weniger nutzlosem Code zur Laufzeit finden Sie unter: http://www.stroustrup.com/bs_faq2.html#constraints , das einige Klassen bereitstellt, die den Test zur Kompilierungszeit effizient durchführen und schönere Fehlermeldungen erzeugen.
Speziell:
template<class T, class B> struct Derived_from {
static void constraints(T* p) { B* pb = p; }
Derived_from() { void(*p)(T*) = constraints; }
};
template<class T> void function() {
Derived_from<T,Baseclass>();
}
unused variable 'p'und unused variable 'pb'?
(void)pb;nachher hinzufügen B* pb = p;.
Sie benötigen keine Konzepte, können aber SFINAE verwenden:
template <typename T>
boost::enable_if< boost::is_base_of<Base,T>::value >::type function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Beachten Sie, dass dies die Funktion nur instanziiert, wenn die Bedingung erfüllt ist, aber keinen vernünftigen Fehler liefert, wenn die Bedingung nicht erfüllt ist.
enable_ifnimmt einen zweiten Parameter, der standardmäßig verwendet wird void. Der Ausdruck enable_if< true, int >::typerepräsentiert den Typ int. Ich kann nicht wirklich verstehen, was Ihre erste Frage ist. Sie können SFINAE für alles verwenden, was Sie möchten, aber ich verstehe nicht ganz, was Sie damit über alle Funktionen hinweg vorhaben.
Seit C ++ 11 benötigen Sie Boost oder nicht mehr static_assert. C ++ 11 führt ein is_base_of und enable_if. In C ++ 14 wird der Convenience-Typ eingeführt enable_if_t. Wenn Sie jedoch mit C ++ 11 nicht weiterkommen, können Sie ihn enable_if::typestattdessen einfach verwenden .
Die Lösung von David Rodríguez kann wie folgt umgeschrieben werden:
#include <type_traits>
using namespace std;
template <typename T>
enable_if_t<is_base_of<Base, T>::value, void> function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Seit C ++ 17 haben wir is_base_of_v. Die Lösung kann weiter umgeschrieben werden in:
#include <type_traits>
using namespace std;
template <typename T>
enable_if_t<is_base_of_v<Base, T>, void> function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Sie können auch einfach die gesamte Vorlage einschränken. Mit dieser Methode können Sie ganze Klassen definieren. Beachten Sie, wie der zweite Parameter von enable_if_tentfernt wurde (er wurde zuvor auf void gesetzt). Der Standardwert ist tatsächlich void, aber es spielt keine Rolle, da wir ihn nicht verwenden.
#include <type_traits>
using namespace std;
template <typename T,
typename = enable_if_t<is_base_of_v<Base, T>>>
void function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Aus der Dokumentation der Vorlagenparameter geht hervor, dass typename = enable_if_t...es sich um einen Vorlagenparameter mit einem leeren Namen handelt. Wir verwenden es einfach, um sicherzustellen, dass die Definition eines Typs vorhanden ist. Insbesondere enable_if_twird nicht definiert, wenn Basekeine Basis von ist T.
Die obige Technik ist als Beispiel in angegeben enable_if.
template <class T : Base>
Sie könnten verwenden Boost - Concept Check ‚s BOOST_CONCEPT_REQUIRES:
#include <boost/concept_check.hpp>
#include <boost/concept/requires.hpp>
template <class T>
BOOST_CONCEPT_REQUIRES(
((boost::Convertible<T, BaseClass>)),
(void)) function()
{
//...
}
Durch Aufrufen von Funktionen in Ihrer Vorlage, die in der Basisklasse vorhanden sind.
Wenn Sie versuchen, Ihre Vorlage mit einem Typ zu instanziieren, der keinen Zugriff auf diese Funktion hat, wird ein Fehler beim Kompilieren angezeigt.
T ist, BaseClass da die deklarierten Mitglieder BaseClassin der Deklaration von wiederholt werden könnten T.