Любопытно повторяющиеся проблемы подклассов, зависящие от параметров шаблона и шаблона
Я пытаюсь заставить работать следующий код
template < class __derived, class __object = typename __derived::Object >
struct Base {
using Derived = __derived;
using Object = __object;
void function(Object o) { return Derived::function(s); }
}
//template < class __derived >
//struct Base {
// using Derived = __derived;
// using Object = typename Derived::Object;
// void function(Object o) { return Derived::function(s); }
//}
template < class __object >
struct Derived : public Base< Derived< __Object > > {
using Object = __object;
void function(Object o) { ... }
}
И я создаю экземпляр объекта, объявив
Derived<double> obj;
Проблема в том, что компилятор утверждает, что не может найти символ Object
внутри Derived
класс при выводе второго параметра шаблона для Base
учебный класс. Та же ошибка также генерируется закомментированной версией.
Я пытаюсь сделать это под вдохновением кода Eigen3, в частности CRTP (CURLYURURURRING Template Pattern), который они используют, чтобы избежать использования виртуальных функций. Eigen3 на самом деле использует traits
класс, но я не могу понять, как имитировать это для настоящего случая. У кого-нибудь есть предложения по этому поводу? Заранее спасибо!
1 ответ
Обычно, если вы хотите, чтобы A наследовал от B, то B не может знать ничего об A, кроме его объявления:
template < class __object >
struct Derived;
К сожалению, вы хотите получить больше, поэтому вам придется использовать черту типа:
template<class __derived>
struct Base_traits {
//using Object = ?????;
};
template<class __object>
struct Base_traits<Derived<__object>> {
using Object = __object; //note, this also can't inspect B.
};
Base
класс может проверить Base_traits
все, что он хочет, потому что черты не проверяют B
совсем.
template < class __derived, class __object = typename Base_traits<__derived>::Object >
struct Base {
using Derived = __derived;
using Object = typename Base_traits<__derived>::Object;
//or
using Object = __object;
Несвязанные, ведущие двойные подчеркивания запрещены для использования смертными, используйте единственное нижнее подчеркивание, за которым следует строчная буква. В качестве альтернативы используйте завершающее подчеркивание.
Также синтаксис
void function(Object o) { return Derived::function(s); }
Не будет работать, потому что эта нотация не может быть использована для upcasts, только для downcasts. Ergo, вы должны использовать static_cast
на this
, Поскольку это смутно некрасиво, я поставил это за функцию:
void foo(Object o) { self()->bar(o); }
private:
__derived* self() {return static_cast<__derived*>(this);}
const __derived* self() const {return static_cast<__derived*>(this);}
};
Полный код: http://coliru.stacked-crooked.com/a/81595b0fcd36ab93