Вызов шаблонного метода, допускающего только подклассы в качестве параметра

Предположим, у меня есть набор классов, унаследованных от одного суперкласса S:

class S{ ... };

class C1 : public S{ ... };
class C2 : public S{ ... };

Тогда предположим, что у меня есть шаблонный метод:

template<class T> void foo(T* instance);

Я хотел бы статически проверить, что foo никогда не вызывается, предоставляя экземпляр суперкласса, а только вызывается, предоставляя один из (конкретных) подклассов (например, явно вызывая foo<C1>(x) например)

Это возможно?

1 ответ

Решение

Сначала мы можем написать черту, чтобы проверить, T происходит от S, но нет S:

template <class Base, class Derived>
using is_strict_base = 
    std::integral_constant<bool,
        std::is_base_of<Base,Derived>::value && 
        !std::is_same<Base,typename std::remove_cv<Derived>::type>::value>;

Ты можешь использовать std::enable_if использовать эту черту:

template<class T>
typename std::enable_if<is_strict_base<S,T>::value>::type
foo(T* instance)
{}

С C++14 вы можете использовать std::enable_if_t чтобы сделать его немного красивее:

template<class T>
std::enable_if_t<is_strict_base<S,T>::value>
foo(T* instance)
{}

Другой вариант заключается в использовании static_assert:

template<class T>
void foo(T* instance)
{
    static_assert(is_strict_base<S,T>::value, 
                  "T must be derived from S, but not S");
}

Это дает вам более приятную ошибку, но я лично считаю, что ограничения типа для функции принадлежат объявлению.

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