Ограничение шаблона времени компиляции C++
В основном у меня есть 4 класса:
- OverVoid
- Мета: это наследует OverVoid
- Физический: который не имеет ничего общего с вышеизложенным
- Move: шаблонный класс
Я хочу, чтобы шаблон перемещения принимал объекты только типа OverVoid, т.е. OverVoid и Meta.
class OverVoid{
public:
virtual ~OverVoid(){
};
};
class Meta: public OverVoid{
};
class Physical{
public:
};
template<typename _Ty>
class Move{
};
Я хочу, чтобы ошибка выводилась во время компиляции, я знаю, что есть способ с boost, но я не могу использовать Boost (проблемы с dev в моей компании)
есть идеи?
3 ответа
Вы можете скрыть определение шаблона для классов не типа OverVoid
template<typename _Ty,
class = typename std::enable_if<std::is_base_of<OverVoid, _Ty>::value>::type>
class Move{
};
Затем вы получаете сообщение об ошибке при попытке скомпилировать класс типа не OverVoid.
int main() {
Move<Meta> a;
Move<OverVoid> b;
Move<Physical> c;
// your code goes here
return 0;
}
Ошибка:
prog.cpp: In function 'int main()':
prog.cpp:29:15: error: no type named 'type' in 'struct std::enable_if<false, void>'
Move<Physical> c;
Самое простое, это просто static_assert
:
template<typename _Ty>
class Move {
static_assert(std::is_base_of<OverVoid, _Ty>::value,
"_Ty must inherit from OverVoid.");
};
Обратите внимание, что это позволяет OverVoid
быть частной или недоступной базой. Если вы хотите требовать, чтобы это была публичная база, вместо этого вы можете потребовать:
static_assert(std::is_convertible<_Ty*, OverVoid*>::value,
"_Ty must inherit publicly from OverVoid.");
Используйте std:: enable_if:
template <typename T>
struct is_overvoid_or_meta
{
static const bool value = false;
};
template <> struct is_overvoid_or_meta<OverVoid>
{
static const bool value = true;
};
template <> struct is_overvoid_or_meta<Meta>
{
static const bool value = true;
};
//Add specialization for all valid types - this allows you to more precisely tell, what types can be used as a template argument for Move
А потом:
template<typename _Ty>
class Move
{
typedef std::enable_if<is_overvoid_or_meta<_Ty>::value, _Ty>::type Type;
};
Вы получите ошибку времени компиляции для каждого типа, это не OverVoid
или же Meta
(или, вообще говоря, для каждого T
, для которого is_overvoid_or_meta<T>::value
является false
- если вы добавите больше из них в будущем, вы можете изменить is_overvoid_or_meta
к более общему, как is_acceptable_by_move
или что-то):
int main()
{
Move<OverVoid> m1;
Move<Meta> m2;
Move<int> m3;
return 0;
}
Выход:
ошибка: нет типа с именем 'type' в 'struct std:: enable_if'
typedef имя типа std::enable_if::value, _Ty>::type Type;
Это очень хорошее решение, потому что его нельзя обмануть - дополнительный параметр шаблона для Move
всегда можно указать вручную (если только OverVoid
а также Meta
не подвергаются клиенту).