В связи с необходимость часто применять CRTP сделал для себя следующий helper.
Пример использования:
template<typename derived_t>
class A : public crtp_t<A, derived_t>
{
public:
void f()
{
derived(this).f_impl();
}
};
Helper решает следующие задачи:
1. Форсирует, что класс derived_t является производным от А.
2. Форсирует, что класс derived_t является MDT (most derived type).
3. Предоставляет функции derived(), с помощью которых удобно конвертировать базовый класс в производный.
Код helper'а:
template<typename base_t, typename derived_t>
struct crtp_helper_t
{
struct inner_t
{
typedef base_t base;
typedef derived_t derived;
};
friend typename inner_t::base;
friend typename inner_t::derived;
crtp_helper_t() {}
};
template<typename base_t, typename derived_t>
class crtp_t : virtual private crtp_helper_t<base_t, derived_t>
{
};
template<typename base_t, typename derived_t>
derived_t& derived(crtp_t<base_t, derived_t>* self)
{
return static_cast<derived_t&>(*self);
}
template<typename base_t, typename derived_t>
derived_t const& derived(crtp_t<base_t, derived_t> const* self)
{
return static_cast<derived_t const&>(*self);
}
Может ещё кому пригодится. Комментарии приветствуются
з.ы. вопросы портирования:
Этот вариант работает под vc71/vc80/g++. Если надо, что б работал под edg c++ надо убрать выделенные typename.
При использовании лучше пистаь не:
class A : public crtp_t<A, derived_t>
а:
class A : public crtp_t<A<derived_t>, derived_t>
т.к. глупая vc80 иначе не понимает (vc71 как ни странно понимает)
Здравствуйте, remark, Вы писали:
R>В связи с необходимость часто применять CRTP сделал для себя следующий helper.
R>Пример использования:
R>Helper решает следующие задачи:
R>1. Форсирует, что класс derived_t является производным от А.
R>2. Форсирует, что класс derived_t является MDT (most derived type).
R>3. Предоставляет функции derived(), с помощью которых удобно конвертировать базовый класс в производный.
R>Может ещё кому пригодится. Комментарии приветствуются
Зачем нужен crtp_helper_t?
R>При использовании лучше пистаь не:
R>R>class A : public crtp_t<A, derived_t>
R>
R>а:
R>R>class A : public crtp_t<A<derived_t>, derived_t>
R>
R>т.к. глупая vc80 иначе не понимает (vc71 как ни странно понимает)
глупый gcc тоже иначе не понимает.
R>
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, remark, Вы писали:
R>>В связи с необходимость часто применять CRTP сделал для себя следующий helper.
R>>Пример использования:
R>>Helper решает следующие задачи:
R>>1. Форсирует, что класс derived_t является производным от А.
R>>2. Форсирует, что класс derived_t является MDT (most derived type).
R>>3. Предоставляет функции derived(), с помощью которых удобно конвертировать базовый класс в производный.
R>>Может ещё кому пригодится. Комментарии приветствуются
NB>Зачем нужен crtp_helper_t?
Что бы форсировать MDT, надо где-то вставить виртуальное наследование.
Пользователя не хочется заставлять наследовать свой класс от crtp_t с помощью виртуального наследования.
Поэтому crtp_t наследуется от crtp_helper_t виртуально.
R>>При использовании лучше пистаь не:
R>>R>>class A : public crtp_t<A, derived_t>
R>>
R>>а:
R>>R>>class A : public crtp_t<A<derived_t>, derived_t>
R>>
R>>т.к. глупая vc80 иначе не понимает (vc71 как ни странно понимает)
NB>глупый gcc тоже иначе не понимает.
Значит это только vc71 умный. И edg.
R>>
Здравствуйте, remark, Вы писали:
R>>>Может ещё кому пригодится. Комментарии приветствуются
NB>>Зачем нужен crtp_helper_t?
R>Что бы форсировать MDT, надо где-то вставить виртуальное наследование.
R>Пользователя не хочется заставлять наследовать свой класс от crtp_t с помощью виртуального наследования.
R>Поэтому crtp_t наследуется от crtp_helper_t виртуально.
для MDT конструктор базы должен быть приватным.
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, remark, Вы писали:
R>>>>Может ещё кому пригодится. Комментарии приветствуются
NB>>>Зачем нужен crtp_helper_t?
R>>Что бы форсировать MDT, надо где-то вставить виртуальное наследование.
R>>Пользователя не хочется заставлять наследовать свой класс от crtp_t с помощью виртуального наследования.
R>>Поэтому crtp_t наследуется от crtp_helper_t виртуально.
NB>для MDT конструктор базы должен быть приватным.
Там у меня там вроде приватное наследование от crtp_helper_t...
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, remark, Вы писали:
NB>>>Зачем нужен crtp_helper_t?
R>>Что бы форсировать MDT, надо где-то вставить виртуальное наследование.
R>>Пользователя не хочется заставлять наследовать свой класс от crtp_t с помощью виртуального наследования.
R>>Поэтому crtp_t наследуется от crtp_helper_t виртуально.
NB>и еще нужно добавить crtp_t во френды
Вообще изначально у меня и был примерно такой подход — конструктор crtp_helper_t приватный и crtp_t во врендах.
А потом я сделал приватное наследование от crtp_helper_t, и вроде как стало чуть попроще/поменьше кода.
Здравствуйте, remark, Вы писали:
R>Здравствуйте, night beast, Вы писали:
NB>>Здравствуйте, remark, Вы писали:
R>>>>>Может ещё кому пригодится. Комментарии приветствуются
NB>>>>Зачем нужен crtp_helper_t?
R>>>Что бы форсировать MDT, надо где-то вставить виртуальное наследование.
R>>>Пользователя не хочется заставлять наследовать свой класс от crtp_t с помощью виртуального наследования.
R>>>Поэтому crtp_t наследуется от crtp_helper_t виртуально.
NB>>для MDT конструктор базы должен быть приватным.
R>Там у меня там вроде приватное наследование от crtp_helper_t...
такой код гсс и комо компилируют
struct B : A<B> {};
struct C : B {};
int main() {
C x;
}
Здравствуйте, night beast, Вы писали:
NB>такой код гсс и комо компилируют
NB>NB>struct B : A<B> {};
NB>struct C : B {};
NB>int main() {
NB> C x;
NB>}
NB>
Да, действительно, облажался.
Значит надо откатиться к предыдущему варианту:
template<typename base_t, typename derived_t> class crtp_t;
template<typename base_t, typename derived_t>
class crtp_helper_t
{
struct inner_t
{
typedef crtp_t<base_t, derived_t> crtp;
typedef base_t base;
typedef derived_t derived;
};
friend typename inner_t::crtp;
friend typename inner_t::base;
friend typename inner_t::derived;
crtp_helper_t() {}
};
template<typename base_t, typename derived_t>
class crtp_t : virtual crtp_helper_t<base_t, derived_t>
{
};
template<typename base_t, typename derived_t>
derived_t& derived(crtp_t<base_t, derived_t>* self)
{
return static_cast<derived_t&>(*self);
}
template<typename base_t, typename derived_t>
derived_t const& derived(crtp_t<base_t, derived_t> const* self)
{
return static_cast<derived_t const&>(*self);
}
Здравствуйте, Kubroid, Вы писали:
K>вопрос чайника — зачам все это надо ?
K>можно маленький пример, попроще. на пальцах.
http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern
Здравствуйте, Kubroid, Вы писали:
K>вопрос чайника — зачам все это надо ?
K>можно маленький пример, попроще. на пальцах.
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Curiously_Recurring_Template_Pattern