Як я можу змусити параметр шаблону T
бути підкласом певного класу Baseclass
? Щось на зразок цього:
template <class T : Baseclass> void function(){
T *object = new T();
}
Як я можу змусити параметр шаблону T
бути підкласом певного класу Baseclass
? Щось на зразок цього:
template <class T : Baseclass> void function(){
T *object = new T();
}
T
походить від Baseclass
. На сьогоднішній день ця перевірка є неявною і не відображається для дозволу на перевантаження. Але якщо ніде не робиться такого неявного обмеження, здається, немає причин для штучного обмеження.
Відповіді:
У цьому випадку ви можете зробити:
template <class T> void function(){
Baseclass *object = new T();
}
Це не буде скомпільовано, якщо T не є підкласом базового класу (або T є базовим класом).
За допомогою компілятора, сумісного з C ++ 11, ви можете зробити щось подібне:
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...
...
}
}
Я перевірив це за допомогою компілятора gcc 4.8.1 всередині середовища CYGWIN - тому він також повинен працювати в середовищах * nix.
template<class TEntity> class BaseBiz { static_assert(std::is_base_of<BaseEntity, TEntity>::value, "TEntity not derived from BaseEntity");
...
Щоб виконати менш марний код під час виконання, ви можете подивитися: http://www.stroustrup.com/bs_faq2.html#constraints, який надає деякі класи, які ефективно виконують перевірку часу компіляції та видають приємніші повідомлення про помилки.
Зокрема:
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'
та unused variable 'pb'
?
(void)pb;
після B* pb = p;
.
Вам не потрібні поняття, але ви можете використовувати 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
}
Зверніть увагу, що це створить функцію лише тоді, коли умова виконана, але вона не дасть помітної помилки, якщо умова не виконана.
enable_if
Займає другий тип параметра , який по замовчуванням void
. Вираз enable_if< true, int >::type
представляє тип int
. Я не можу зрозуміти, що саме ваше перше запитання, ви можете використовувати SFINAE, що завгодно, але я не зовсім розумію, що ви маєте намір робити з цим за всіма функціями.
З C ++ 11 вам не потрібен Boost або static_assert
. C ++ 11 вводить is_base_of
та enable_if
. C ++ 14 представляє зручний тип enable_if_t
, але якщо ви застрягли в C ++ 11, ви можете просто використовувати його enable_if::type
.
Рішення Девіда Родрігеса можна переписати таким чином:
#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
}
З C ++ 17 ми маємо is_base_of_v
. Рішення можна переписати на:
#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
}
Ви також можете просто обмежити весь шаблон. Ви можете використовувати цей метод для визначення цілих класів. Зверніть увагу, як enable_if_t
був вилучений другий параметр (раніше його було встановлено як void). Його значення за замовчуванням насправді void
, але це не має значення, оскільки ми його не використовуємо.
#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
}
З документації параметрів шаблону ми бачимо, що typename = enable_if_t...
це параметр шаблону з порожнім ім'ям. Ми просто використовуємо його, щоб переконатися, що існує визначення типу. Зокрема, enable_if_t
не буде визначено, якщо Base
не є базою T
.
Методика, наведена вище, наведена як приклад в enable_if
.
template <class T : Base>
Ви можете використовувати підштовхування Concept Check «и 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()
{
//...
}
Викликаючи функції всередині вашого шаблону, які існують у базовому класі.
Якщо ви спробуєте створити шаблон для вашого типу, який не має доступу до цієї функції, ви отримаєте помилку під час компіляції.
T
це BaseClass
тому, що заявлені члени в BaseClass
можуть бути повторені в декларації T
.