Ограничить параметр шаблона C ++ подклассом - PullRequest
65 голосов
/ 04 июля 2010

Как заставить параметр шаблона T быть подклассом определенного класса Baseclass? Примерно так:

template <class T : Baseclass> void function(){
    T *object = new T();

}

Ответы [ 7 ]

74 голосов
/ 23 сентября 2013

С компилятором, совместимым с 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 окружениях.

45 голосов
/ 04 июля 2010

В этом случае вы можете сделать:

template <class T> void function(){
    Baseclass *object = new T();

}

Это не скомпилируется, если T не является подклассом Baseclass (или T равен Baseclass).

43 голосов
/ 05 июля 2010

Чтобы выполнить меньше бесполезного кода во время выполнения, вы можете посмотреть на: 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>();
}
10 голосов
/ 05 июля 2010

Вам не нужны понятия, но вы можете использовать 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
}

Обратите внимание, что это создаст экземпляр функции только при выполнении условия, но не даст ощутимой ошибки, если условие не будет выполнено.

4 голосов
/ 04 июля 2010

Вы можете использовать Boost 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()
{
    //...
}
1 голос
/ 20 марта 2019

Начиная с C ++ 11 вам не нужно Boost или static_assert. C ++ 11 представляет is_base_of и enable_if. C ++ 14 вводит вспомогательный тип enable_if_t, но если вы застряли в C ++ 11, вы можете просто использовать вместо него enable_if::type.

Альтернатива 1

Дэвид Родригес решение может быть переписано следующим образом:

#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
}

Альтернатива 2

Начиная с 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
}

Альтернатива 3

Вы также можете просто ограничить весь шаблон. Вы можете использовать этот метод для определения целых классов. Обратите внимание, как был удален второй параметр 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.

0 голосов
/ 04 июля 2010

Вызывая функции внутри вашего шаблона, которые существуют в базовом классе.

Если вы попытаетесь создать экземпляр шаблона с типом, который не имеет доступа к этой функции, вы получите ошибку во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...