Разрешение порядка инициализации CRTP

У меня есть некоторая зависимость от CRTP, которую я не знаю, как решить. В идеале я хочу поместить в базовый класс как можно больше вещей, таких как функции, поэтому мне не нужно переопределять их для каждого класса, который их наследует. Кажется, это вызывает проблему с порядком инициализации, где result_type зависит от типа, который еще не инициализирован. Вот пример: https://godbolt.org/z/YpfcPB

А вот код:

template<typename T>
struct CRTP_Derived;

template<typename Derived>
struct CRTP
{
    using result_type = typename Derived::result_type;

};

template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>>
{
    using result_type = T;
};

int main()
{
    CRTP_Derived<int> a;
    return 0;
}

person lightxbulb    schedule 17.10.2019    source источник
comment
Инициализировать здесь не то слово. Проблема связана с тем, когда тип класса считается завершенным.   -  person aschepler    schedule 17.10.2019
comment
@aschepler Создать экземпляр? Если бы я мог определить порядок, у меня не было бы проблем. Вот что на самом деле делает черта — она откладывает result_type на потом.   -  person lightxbulb    schedule 17.10.2019


Ответы (2)


Я также использовал отдельный тип признаков для таких проблем. Вы можете немного уменьшить необходимый шаблон, если сделаете черты вторым параметром шаблона, вместо того, чтобы требовать от пользователей специализации отдельного шаблона:

template<typename Derived, typename Traits>
struct CRTP
{
    using result_type = typename Traits::result_type;
};

template<typename T>
struct CRTP_Derived_Traits
{
    using result_type = T;
};

template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>, CRTP_Derived_Traits<T>>
{
};

int main()
{
    CRTP_Derived<int> a;
    return 0;
}
person aschepler    schedule 17.10.2019

Обходной путь, который я нашел, - вынести typedef в отдельный класс, но я был бы рад увидеть другие решения. https://godbolt.org/z/a7NCE2

template<typename T>
struct CRTP_Derived;

template<typename Derived>
struct traits;

template<typename T>
struct traits<CRTP_Derived<T>>
{
    using result_type = T;
};

template<typename Derived>
struct CRTP
{
    using result_type = typename traits<Derived>::result_type;
};

template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>>
{
    using result_type = T;
};

int main()
{
    CRTP_Derived<int> a;
    return 0;
}
person lightxbulb    schedule 17.10.2019