Я удивление являюсь там каким-либо способом установить ограничения на шаблонный класс?
Укажите, что каждый тип, которым заменяют в шаблоне, должен иметь определенного предка (поймите некоторый интерфейс).
template < class B > //and every B must be a child of abstract C
class A {
public:
B * obj;
int f() {
return B::x + this->obj->f();
}
};
Как => в haskell
func :: (Ord a, Show b) => a -> b -> c
Вы можете использовать BOOST_STATIC_ASSERT
или аналогичную библиотеку для утверждения ваших ограничений на параметр шаблона.
Например:
#include <limits>
#include <boost/static_assert.hpp>
template <class UnsignedInt>
class myclass
{
private:
BOOST_STATIC_ASSERT((std::numeric_limits<UnsignedInt>::digits >= 16)
&& std::numeric_limits<UnsignedInt>::is_specialized
&& std::numeric_limits<UnsignedInt>::is_integer
&& !std::numeric_limits<UnsignedInt>::is_signed);
public:
/* details here */
};
РЕДАКТИРОВАТЬ : В вашем примере вы можете написать
template < class B >
class A {
BOOST_STATIC_ASSERT(boost::is_base_of<C, B>);
public:
B * obj;
int f() {
return B::x + this->obj->f();
}
};
Будущая версия C ++ будет поддерживать это изначально с использованием концепций (которые не не попаду в C ++ 11).
Один из способов решения проблемы - использовать специализацию для фиктивного параметра шаблона:
class C {};
template <class B, class dummy=void>
class A;
template <class B>
class A<B, typename enable_if<is_base_and_derived<C, B> >::type>
{
// class definition here
};
struct D : C {};
A<D> d; // fine
A<int> n; // compile error - undefined class A<B>
Я поместил автономные определения enable_if
и is_base_and_dehibited
здесь .
Следующее работает в VC10 с использованием static_assert. Я только что видел, как это используют, и особо не разбирался в том, что на самом деле делает static_assert - возможно, кто-то еще сможет на это ответить.
#include <type_traits>
class Base
{
};
class Derived : public Base
{
};
class SomeRandomClass
{
};
template<typename T>
class A
{
static_assert(std::tr1::is_base_of<Base, T>::value, "T not derived from Base");
};
int _tmain(int argc, _TCHAR* argv[])
{
argc; argv;
//
// This will compile
A<Derived> a;
//
// This will throw a compilation error
A<SomeRandomClass> b;
return 0;
}
Вывод компилятора:
1>d:\temp\aaa\aaa\aaa.cpp(25): error C2338: T not derived from Base
1> d:\temp\aaa\aaa\aaa.cpp(41) : see reference to class template instantiation 'A<T>' being compiled
1> with
1> [
1> T=SomeRandomClass
1> ]
Вы можете использовать такой трюк (если вы не хотите использовать Boost):
class Base
{
public:
static const int TEMPLATE_REQUIRES_BASE_CLASS = 0;
};
class Correct : public Base
{
};
class Incorrect
{
};
template <typename T>
class TMPL
{
static const int TEMPLATE_REQUIRES_BASE_CLASS = T::TEMPLATE_REQUIRES_BASE_CLASS;
T *m_t;
};
void main()
{
TMPL<Correct> one; // OK
TMPL<Incorrect> two; // Will not compile
}
Первая строка будет компилироваться. Второй не будет компилироваться и выдаст следующую ошибку:
test.cpp
test.cpp(18) : error C2039: 'TEMPLATE_REQUIRES_BASE_CLASS' : is not a member of 'Incorrect'
test.cpp(12) : see declaration of 'Incorrect'
test.cpp(25) : see reference to class template instantiation 'TMPL<T>' being compiled
with
[
T=Incorrect
]
test.cpp(18) : error C2065: 'TEMPLATE_REQUIRES_BASE_CLASS' : undeclared identifier
test.cpp(18) : error C2057: expected constant expression
Шаблоны - это своего рода утиная типизация в C++.
Если ваш класс поддерживает все, что использует шаблон, то он может быть использован в качестве аргумента шаблона, в противном случае - нет.
Если в вашем шаблоне есть что-то вроде
C *instance;
void foo(T *t)
{
instance = t;
}
то вы принуждаете T быть производным от C (или, по крайней мере, совместимым с присваиванием для указателей)