Jak mogę wymusić, T
aby parametr szablonu był podklasą określonej klasy Baseclass
? Coś takiego:
template <class T : Baseclass> void function(){
T *object = new T();
}
Jak mogę wymusić, T
aby parametr szablonu był podklasą określonej klasy Baseclass
? Coś takiego:
template <class T : Baseclass> void function(){
T *object = new T();
}
T
pochodzi z Baseclass
. W tej chwili to sprawdzenie jest niejawne i nie jest widoczne w celu rozpoznania przeciążenia. Ale jeśli nigdzie nie ma takiego domniemanego ograniczenia, wydaje się, że nie ma powodu do sztucznego ograniczenia.
Odpowiedzi:
W takim przypadku możesz:
template <class T> void function(){
Baseclass *object = new T();
}
Nie zostanie to skompilowane, jeśli T nie jest podklasą klasy podstawowej (lub T jest klasą podstawową).
Korzystając z kompilatora zgodnego z C ++ 11, możesz zrobić coś takiego:
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...
...
}
}
Przetestowałem to przy użyciu kompilatora gcc 4.8.1 w środowisku CYGWIN - więc powinno działać również w środowiskach * nix.
template<class TEntity> class BaseBiz { static_assert(std::is_base_of<BaseEntity, TEntity>::value, "TEntity not derived from BaseEntity");
...
Aby wykonać mniej bezużyteczny kod w czasie wykonywania, możesz zajrzeć na stronę: http://www.stroustrup.com/bs_faq2.html#constraints, która zawiera kilka klas, które wydajnie wykonują test czasu kompilacji i generują ładniejsze komunikaty o błędach.
W szczególności:
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'
i unused variable 'pb'
?
(void)pb;
po B* pb = p;
.
Nie potrzebujesz pojęć, ale możesz użyć SFINAE:
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
}
Zauważ, że spowoduje to utworzenie instancji funkcji tylko wtedy, gdy warunek zostanie spełniony, ale nie zapewni rozsądnego błędu, jeśli warunek nie zostanie spełniony.
enable_if
Trwa drugi typ parametru, który domyślnie void
. Wyrażenie enable_if< true, int >::type
reprezentuje typ int
. Nie bardzo rozumiem, jakie jest twoje pierwsze pytanie, możesz użyć SFINAE do wszystkiego, co chcesz, ale nie do końca rozumiem, co zamierzasz z tym zrobić we wszystkich funkcjach.
Od C ++ 11 nie potrzebujesz Boost ani static_assert
. C ++ 11 wprowadza is_base_of
i enable_if
. C ++ 14 wprowadza wygodny typ enable_if_t
, ale jeśli utkniesz z C ++ 11, możesz po prostu użyć enable_if::type
zamiast tego.
Rozwiązanie Davida Rodrígueza można przepisać w następujący sposób:
#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
}
Od C ++ 17 mamy is_base_of_v
. Rozwiązanie można dalej przepisać na:
#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
}
Możesz także ograniczyć cały szablon. Możesz użyć tej metody do definiowania całych klas. Zwróć uwagę, jak enable_if_t
usunięto drugi parametr z (poprzednio był ustawiony na void). Jego domyślna wartość to faktycznie void
, ale nie ma to znaczenia, ponieważ jej nie używamy.
#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
}
Z dokumentacji parametrów szablonu widzimy, że typename = enable_if_t...
jest to parametr szablonu z pustą nazwą. Używamy go po prostu do upewnienia się, że istnieje definicja typu. W szczególności enable_if_t
nie zostanie zdefiniowany, jeśli Base
nie jest podstawą T
.
Powyższa technika jest podana jako przykład w enable_if
.
template <class T : Base>
Można użyć Boost, Concept Sprawdź „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()
{
//...
}
Wywołując funkcje wewnątrz szablonu, które istnieją w klasie bazowej.
Jeśli spróbujesz utworzyć wystąpienie szablonu z typem, który nie ma dostępu do tej funkcji, zostanie wyświetlony błąd kompilacji.
T
to, że tak jest,BaseClass
ponieważ zadeklarowani członkowie BaseClass
mogliby zostać powtórzeni w deklaracji T
.