Как убедиться, что параметр шаблона является подтипом требуемого типа?
У меня есть класс шаблона, я хочу сделать следующее
- Убедитесь, что объект создается только в том случае, если переданный параметр шаблона является подтипом желаемого типа
- Общайтесь с пользователем кода перед тем, что параметр шаблона должен удовлетворять
(1) автоматически рассматривается в том смысле, что если переданный параметр шаблона не поддерживает некоторую функцию, которую класс использует, код не будет компилироваться. Но эта ошибка может быть обнаружена довольно поздно. Я хочу, чтобы чеки были как можно раньше. То, что я также хочу сделать, заключается в том, что должно быть очевидно, что передаваемый параметр шаблона должен быть получен из базового типа, который я предоставляю.
Во-первых, это ошибочно? и если нет, то как мне это сделать? (простейший способ, пожалуйста, С++ все еще новичок для меня)
Благодаря stackoverflow, вы действительно ускорили мою скорость обучения С++.
Ответы
Ответ 1
Учитывая некоторый полный тип 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
};
Если вы используете компилятор С++ 03 с TR1, вы можете использовать std::tr1::is_base_of
вместо boost::is_base_of
; если вы используете компилятор С++ 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
as-a MyBase
(в большинстве контекстов).
Ссылки Doc:
Boost. StaticAssert
Boost. TypeTraits
Ответ 2
Из "Modern С++ 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.
Ответ 3
Да, это автоматически берется в том случае, если параметр не поддерживает то, что вы делаете с ним, это приведет к ошибке компиляции. Проверка вручную, если тип является подтипом другого типа, может выполняться только (AFAIK) во время выполнения, что намного позже времени компиляции. Я не знаю, что вы подразумеваете под этой ошибкой, которую обнаруживают поздно, время компиляции уже достигнуто. Кроме того, если все проверяли тип параметров своего шаблона, STL не мог работать с указателями, а также с фактическими итераторами на основе классов и не был бы почти таким же гибким.
Что касается того, чтобы ваш пользователь знал требования, просто укажите их в документации.