Ограничение шаблона времени компиляции 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 не подвергаются клиенту).

Другие вопросы по тегам