У меня есть класс, который получает свой базовый тип в качестве аргумента шаблона, и я хочу, чтобы мой производный класс вызывал функцию print. Эта функция должна использовать производную реализацию по умолчанию, но если базовый класс имеет функцию печати, она должна использовать базовую реализацию.
#include <iostream>
class BaseWithPrint {
public:
static void print(int i) { std::cout << "Base::print\n"; }
};
class BaseWithoutPrint {
};
template <typename B>
class Derived : public B {
public:
static void print(bool b) { std::cout << "Derived::bool_print\n"; }
template <typename T>
static void print(T t) { std::cout << "Derived::print\n"; }
void Foo() {
print(1);
print(true);
print("foo");
}
};
int main()
{
Derived<BaseWithPrint> d1;
d1.Foo();
Derived<BaseWithoutPrint> d2;
d2.Foo();
return 0;
}
Этот код вызывает только производную версию print
.
Код можно посмотреть на
«Этот код вызывает только производную версию печати» - Ага. это сверхточно. Нигде в этом коде не предпринимается никаких попыток вызвать B::print
, поэтому, естественно, он никогда не будет вызван. Это не CRTP. CRTP будет производным от базового шаблона, подчиненного производному классу. Например. производный класс: public Base<Derived>.
Ах да, я совсем запутался с CRTP. Я отредактирую это.
Если вы знать, что базовый класс будет иметь какой-то print
, то вы можете добавить using B::print
в свой производный класс. Если в производном не будет найдено идеальное совпадение, он проверит базу.
Чтобы справиться с этим для случая, когда мая является базой print
, я думаю, вам нужно прибегнуть к SFINAE. Лучший подход SFINAE действительно будет зависеть от вашей реальной ситуации. Вот как я решил вашу примерную проблему:
template <class T, class = void>
struct if_no_print_add_an_unusable_one : T {
// only ever called if derived calls with no args and neither
// the derived class nor the parent classes had that print.
// ie. Maybe best to force a compile fail:
void print();
};
template <class T>
struct if_no_print_add_an_unusable_one <T, decltype(T().print(int()))> : T {};
//====================================================================
template <class B>
class Derived : public if_no_print_add_an_unusable_one<B> {
using Parent = if_no_print_add_an_unusable_one<B>;
using Parent::print;
public:
// ... same as before
};
Я предполагаю, что ваш фактический CRTP будет каким-то дальнейшим производным классом от
Derived<>
. Если это так, вам нужно будет использовать SFINAE в функцииDerived::print(T t)
, чтобы выбрать реализациюB
или «по умолчанию» вDerived