C ++ шаблонная специализация через базовый класс - PullRequest
1 голос
/ 01 ноября 2009

Я хочу, чтобы компилятор кричал, когда я вызываю конструктор foo с классом это НЕ получено из _base *. Текущий код допускает только сам foo <_base *>. любой простое решение?

class _base
{
public:
    // ...
};

class _derived: public _base
{
public:
    // ...
};

template <typename T>
class foo
{
public:
    foo ()      { void TEMPLATE_ERROR; }
};

template <> foo<_base*>::foo () 
{
    // this is the only constructor
}

основной код:

foo<_base*>    a;    // should work 
foo<_derived*> b;    // should work (but doesnt)
foo<int*>      c;    // should not work (and infact doesnt)

Ответы [ 3 ]

4 голосов
/ 01 ноября 2009

Используйте SFINAE (через enable_if) и черту типа Boost's is_convertible :

template <typename T, typename Enabled = void>
class foo
{
private:
    foo(); // Constructor declared private and not implemented.
};

template <typename T>
class foo<T, typename enable_if<is_convertible<T, _base*> >::type>
{
public:
    foo() { /* regular code */ }
};

(не проверено, на этом компьютере не установлен Boost.)

3 голосов
/ 01 ноября 2009

Без Boost вы можете использовать что-то вроде следующего, чтобы определить, может ли указатель на тип неявно приводиться к другому указателю на тип:

template <class Derived, class Base>
struct IsConvertible
{
    template <class T>
    static char test(T*);

    template <class T>
    static double test(...);

    static const bool value = sizeof(test<Base>(static_cast<Derived*>(0))) == 1;
};

Чтобы вызвать ошибку во время компиляции, теперь вы можете использовать value в выражении, которое вызывает ошибку, если оно ложно, например typedef массива отрицательного размера.

template <typename T>
class foo
{
public:
    foo ()
    {
        typedef T assert_at_compile_time[IsConvertible<T, _base>::value ? 1 : -1];
    }
};
1 голос
/ 01 ноября 2009

Я понимаю, что вы не используете boost в своем проекте, но, возможно, вы могли бы скопировать и вставить некоторые его части.

Я нашел более простое решение вашей проблемы с помощью boost:

template <typename T>
class foo
{
public:
    foo () {
        BOOST_STATIC_ASSERT((boost::is_convertible<T,_base*>::value));
    }
};

Не требует дополнительных параметров шаблона, также не требуется специализация шаблона. Я проверил это с бустом 1.40.

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