Любопытно повторяющиеся проблемы подклассов, зависящие от параметров шаблона и шаблона

Я пытаюсь заставить работать следующий код

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

Другие вопросы по тегам