Как убедиться, что параметр шаблона является подтипом нужного типа? - PullRequest
22 голосов
/ 11 августа 2011

У меня есть класс шаблона, я хочу сделать следующее:

  1. Убедитесь, что объект создается только в том случае, если переданный параметр шаблона является подтипом нужного типа
  2. Информирование пользователя исходного кода о том, что должен удовлетворять параметр шаблона,

(1) автоматически обрабатывается в том смысле, что передаваемый параметр шаблона не поддерживает некоторые функции.то, что класс использует код, не будет компилироваться.Но эта ошибка может быть обнаружена довольно поздно.Я хочу, чтобы проверки были как можно раньше.Чего я также хочу добиться, так это того, чтобы сразу было очевидно, что передаваемый параметр шаблона должен быть получен из базового типа, который я предоставляю.

Во-первых, это неправильно?и если нет, то как мне это сделать?(самый простой способ, пожалуйста, C ++ все еще для меня новичок)

Благодаря stackoverflow, вы действительно ускорили мою скорость обучения C ++.

Ответы [ 3 ]

42 голосов
/ 11 августа 2011

Учитывая некоторый полный тип MyBase, следующее приведет к ошибке времени компиляции, если T не получено из MyBase:

#include <boost/type_traits/is_base_of.hpp>
#include <boost/static_assert.hpp>

template<typename T>
class Foo {
    BOOST_STATIC_ASSERT_MSG(
        (boost::is_base_of<MyBase, T>::value),
        "T must be a descendant of MyBase"
    );
    // Foo implementation as normal
};

Если вы используете компилятор C ++ 03 с TR1, вы можете использовать std::tr1::is_base_of вместо boost::is_base_of; если вы используете компилятор C ++ 11, вы можете использовать std::is_base_of вместо boost::is_base_of и ключевое слово static_assert вместо макроса BOOST_STATIC_ASSERT_MSG:

#include <type_traits>

template<typename T>
class Foo {
    static_assert(
        std::is_base_of<MyBase, T>::value, 
        "T must be a descendant of MyBase"
    );
    // Foo implementation as normal
};

N.b. это даст true_type для частных и неоднозначных типов, поэтому этого недостаточно, если вам действительно нужно рассматривать T как-10 * MyBase (в большинстве контексты).

Ссылки на документы:
Повышение . StaticAssert
Повышение . TypeTraits

4 голосов
/ 11 августа 2011

В «Современном C ++ Design», глава 2.7 («Обнаружение конвертируемости и наследования во время компиляции»): вы можете использовать sizeof трюк:

typedef char Small;
class Big { char dummy[2]; };

Small Test(Base1);
Big Test(...);

const bool isSubclassOfBase1 = sizeof(Test(Derived1())) == sizeof(Small);

Он использует тот факт, что sizeof(...)может определить тип, для которого вычисляется выражение, и поскольку возвращаемые значения имеют разные размеры, проверка == оценивается как true или false.Если Derived1 действительно является базой Base1, выбрана Small Test(Base1); перегрузка и isSubclassOfBase1 будет истинным.

Исходя из этого, вы можете инкапсулировать проверку и сделать статическое утверждение, чтобы оно не сработало во время компиляции:

#include <boost/static_assert.hpp>

class A {};
class B: public A {};
class C {};

template<class Base, class Derived>
struct SubclassCheck
{
    typedef char Yes;
    class No { char dummy[2]; };

    static Yes Test(Base);
    static No Test(...);
    enum {
        Value = (sizeof(Test(*(Derived*)NULL)) == sizeof(Yes))
    };
};

#define CHECK_DERIVES(b,d)\
    BOOST_STATIC_ASSERT((SubclassCheck<b,d>::Value));

int
main()
{
    CHECK_DERIVES(A, B);
    // CHECK_DERIVES(A, C); // fails
}

Вы можете использовать любую другую реализацию статического утверждения, не обязательно Boost.

0 голосов
/ 11 августа 2011

Да, это выполняется автоматически в том случае, если параметр не поддерживает то, что вы делаете с ним, может произойти ошибка компиляции.Проверка вручную, является ли тип подтипом другого типа, может быть выполнена (AFAIK) только во время выполнения, что на намного позже времени компиляции.Я не знаю, что вы подразумеваете под этой ошибкой, обнаруживаемой поздно, время компиляции наступает раньше.Кроме того, если бы каждый проверял тип своих параметров шаблона, STL не мог работать с указателями, а также с реальными итераторами на основе классов, и не был бы почти таким же гибким.требования, просто укажите их в документации.

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