Как я могу заставить параметр шаблона 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 не является подклассом Baseclass (или 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
это a, BaseClass
потому что объявленные члены BaseClass
могут повторяться в объявлении T
.