Есть два способа сделать это.
Во-первых, через скрытый фиктивный параметр шаблона, который использует std::enable_if
с условием std::is_base_of<A, T>::value
. Если последнее выражение оценивается как false
, то вложенное type
не существует в std::enable_if
. Если вы использовали это для перегруженных функций, SFINAE означает, что «сбой замены не является ошибкой», и рассматриваемая перегрузка будет удалена из набора жизнеспособных функций. Однако в этой ситуации нет другого шаблона класса, соответствующего вашему вызову, и тогда вы получите ошибку времени компиляции.
SFINAE — очень тонкий механизм, и в нем легко ошибиться. Например. если у вас есть несколько специализаций классов с разными условиями SFINAE, вы должны убедиться, что все они не перекрываются, иначе вы получите двусмысленность.
Во-вторых, вы можете сделать простой static_assert
с std::is_base_of<A,T>::value
внутри тела класса. Преимущество этого метода заключается в том, что вы также указываете более читаемое сообщение об ошибке по сравнению с методом SFINAE. Недостатком является то, что вы всегда получаете ошибку, и вы не можете молча подавить этот конкретный шаблон и выбрать другой. Но в целом я думаю, что этот метод рекомендуется в вашем случае.
#include<type_traits>
class A {};
class C: public A {};
class D {};
// first alternative: SFINAE on hidden template parameter
template
<
typename T,
typename /* dummy */ = typename std::enable_if<
std::is_base_of<A, T>::value
>::type
>
class B
{
};
// second alternative: static_assert inside class
template
<
typename T
>
class E
{
static_assert(std::is_base_of<A, T>::value, "A should be a base of T");
};
int main()
{
B<A> b1;
B<C> c1;
//B<D> d1; // uncomment this line to get a compile-time error
E<A> b2;
E<C> c2;
//E<D> d2; // uncomment this line to get a compile-time error
return 0;
}
Как было указано в комментариях, вы можете использовать либо достойный компилятор C++11 (VC++ 2010 или новее, gcc 4.5 или новее), либо библиотеки Boost или TR1, чтобы получить функциональность <type_traits>
. Однако обратите внимание, что std::is_base_of<A, A>::value
оценивается как true
, а старый boost::is_base_of<A, A>::value
раньше оценивался как false
.
person
TemplateRex
schedule
15.08.2012
static_assert
иstd::is_same
(для A) иstd::is_base_of
(для производных). Я напишу пример. Я думаю, чтоstd::enable_if
тоже мог бы это сделать, но я не могу сказать, что использовал его. - person chris   schedule 15.08.2012a
иb
работают, аc
— нет). Если у вас нет С++ 11 (для статического утверждения), я чувствую, чтоstd::enable_if
может помочь, но я не совсем уверен, как его использовать. Это также не даст четкого сообщения об ошибке. - person chris   schedule 15.08.2012type_traits
. Где мне искатьstatic_assert
,std::is_base_of
иstd::enable_if
? - person rid   schedule 15.08.2012static_assert
предназначен только для C++11, и на самом деле кажется, чтоenable_if
тоже, хех.is_base_of
тоже, поэтому я думаю, что для этого требуется С++ 11, потому что я не могу придумать другого гладкого способа сделать это. Чтобы использовать это, вам нужен компилятор с поддержкой этих функций и опция-std=c++11
. - person chris   schedule 15.08.2012enable_if
иis_base_of
, которые можно использовать в C++03. Остальные являются частью C++ по состоянию на прошлый год, так что да, они довольно новые по сравнению с материалом C++03. Метапрограммирование действительно эволюционировало благодаря этому дополнению. Boost — это то, без чего почти не могут обойтись пользователи C++03, и пользователи C++11 тоже получают от этого пользу. Мне удалось просто проигнорировать его существование, в то время как стандартный C++ копирует их идеи. - person chris   schedule 15.08.2012