Как задать ограничения на параметры шаблонных классов?

Mama Bullki

Есть абстрактный класс M и классы A, B и C, для которых М - родительский класс, и в них реализованы все абстрактные методы класса М. Нужно создать шаблонный класс

template <class t=""> class S{ ... };
</class>

в котором качестве шаблона используются классы A, B или C. Можно как-то указать, что M должен быть родительским классом для Т?

4 ответа

Mama Bullki

А если у вас старый компилятор, то можно пойти длинным путем:

class M
{
    virtual void f() const = 0;
};

class A : public M
{
    virtual void f() const
    {
        std::cout << "A" << std::endl;
    }
};

class B
{
};

template<typename d,="" typename="" b="">
class IsDerivedFrom
{
    class No {};
    class Yes { No no[2]; };
    static Yes Test(B*);
    static No  Test(...);
public:
    enum { Is = sizeof(Test(static_cast<d*>(0))) == sizeof(Yes) };
};

template <class t,="" int="IsDerivedFrom<T,M">::Is>
class S
{
};

template <class t="">
class S<t,0>
{   S() { char * p = (int*)0; }
};


int main() 
{
    S<a> s1;
    S<b> s2;

    return 0;
}
</b></a></t,0></class></class></d*></typename>

Зато работает на старых компиляторах, которые не знают C++ 11.


Mama Bullki

Вас спасет std::is_base_of:

struct M {};

struct A: public M {};

struct B {};

template<class t,="" typename="std::enable_if_t<std::is_base_of<M,T">::value>>
struct S {};


int main(int argc, const char * argv[])
{
    S<a> a;
    S<b> b;
}
</b></a></class>


Mama Bullki

Один из способов - это просто объявить, например, typedef для базового класса шаблонного параметра внутри шаблонного класса. Если шаблонный параметр не имеет такого базового класса, то будет выдано сообщение об ошибке.

Например,

#include <iostream>

class M
{
    virtual void f() const = 0;
};

class A : public M
{
    virtual void f() const
    {
        std::cout << "A" << std::endl;
    }
};

class B
{
};

template <class t="">
class S
{
    typedef typename T::M Base;
};

int main() 
{
    S<a> s1;
//  S<b> s2;

    return 0;
}
</b></a></class></iostream>

Если раскомментировать в этой программе закомментированное предложение, то компилятор выдаст сообщение об ошибке.


Mama Bullki

Можно использовать std::is_base_of:

#include <iostream>
#include <type_traits>

class M {
public:
    virtual void f() = 0;
};

class A: public M {
public:
    virtual void f() { std::cout << "class a\n"; }
};

class B {
public:
    virtual void f() { std::cout << "class b\n"; }
};

template<class t,="" class="typename" std::enable_if<std::is_base_of<m,="" t="">::value>::type>
class S
{
public:
    T t;
    void f() { this->t.f(); }
};

int main() {
    S<a> a;
    //S<b> b;
    return 0;
}
</b></a></class></type_traits></iostream>

Если раскомментировать S<B> b, то выдастся ошибка при компиляции.

licensed under cc by-sa 3.0 with attribution.