Вы можете сделать это следующим образом:
typedef char (&yes)[1];
typedef char (&no )[2];
template<class container>
struct class_helper
{
template<typename member> static no has_implemented(member);
template<typename member> static yes has_implemented(member container::*);
};
template<class derived>
class base
{
protected:
base() {}
public:
void foo()
{
static_assert(
sizeof(class_helper<derived>::has_implemented(&derived::foo)) == sizeof(yes),
"derived::foo not implemented"
);
static_cast<derived*>(this)->foo();
}
};
Но вам нужно выполнить static_assert для каждой определенной вами интерфейсной функции.Можно использовать enable_if, чтобы сделать его более общим:
static_cast<typename enable_if_c<
sizeof(class_helper<derived>::has_member(&derived::foo)) == sizeof(yes), derived
>::type*>(this)->foo();
Этот метод имеет недостаток, заключающийся в том, что вам приходится сталкиваться с ошибками компилятора, когда «foo» не реализован в «производном».
Дайте мне подумать об этом.Может быть, у меня есть лучшее решение для этого случая в ближайшее время;)
РЕДАКТИРОВАТЬ: Хорошо, я бы предпочел следующее решение:
template<class derived>
class base
{
template<std::size_t n> struct test {
static_assert(n != sizeof(no), "derived doesn't implement used interface method");
};
protected:
base() {}
public:
void bar()
{
static_cast<derived*>(this)->bar();
test<sizeof(class_helper<derived>::has_implemented(&derived::bar))>();
}
};
Обратите внимание, что вам нужно определить конструктор по умолчанию длябазовый класс в «защищенном» разделе.Если вы этого не сделаете, вызов функции-члена может вызвать нарушение прав доступа, так как он может получить доступ к памяти, которая не была выделена.Не безопасно объявлять объекты типа «base».