Я реализовал Политику, используя CRTP. Политика требует Base
класс, чтобы иметь функцию с именем foo:
template<typename Base>
struct Policy<Base> {
// ...
Base* b(){ return static_cast<Base*>(this); }
void do(){ b()->foo(); }
};
У меня есть один класс под названием Widget
который использует мою политику. Widget
инвентарь foo
и все нормально
struct Widget : Policy<Widget> {
// ...
void foo();
};
Эта проблема: У меня также есть тип под названием OldWidget
который реализует функциональность foo
в функции с именем oldFoo
:
struct OldWidget : Policy<OldWidget> {
// ...
void oldFoo();
};
Я не хочу модифицировать OldWidget (помимо расширения его политикой). Я не хочу использовать AdaptedOldWidget
:
struct AdaptedOldWidget : OldWidget, Policy<AdaptedOldWidget> {
void foo(){ oldFoo(); }
};
Лучше всего было бы расширить мои существующие policy_traits
класс что-то вроде:
template<typename T>
struct policy_traits {};
template<>
struct policy_traits<Widget> {
// typedefs...
member_function_name = foo;
};
template<>
struct policy_traits<OldWidget> {
// typedefs
member_function_name = oldFoo;
};
Так, что я могу реализовать Политику следующим образом:
template<typename Base>
struct Policy<Base> {
// ...
Base* b() { return static_cast<Base*>(this); }
void do(){ b()->policy_traits<Base>::member_function_name(); }
};
Есть ли что-нибудь подобное в C ++?
Предложенное решениеЯ мог бы сделать следующее:
template<typename Base>
struct Policy<Base> : Policy_Member_Traits<Base> {
// ...
Base* b(){ return static_cast<Base*>(this); }
void do(){ foo_wrapper(); }
};
template<typename T> struct Policy_Member_Traits { };
template<> struct Policy_Member_Traits<Widget> {
void foo_wrapper(){ static_cast<T*>(this)->foo(); }
};
template<> struct Policy_Member_Traits<OldWidget> {
void foo_wrapper(){ static_cast<T*>(this)->oldFoo(); }
};
Надеемся, что есть лучший способ добиться этого.
Вот пример того, как специализируется выборочно. Сначала несколько примеров классов:
#include <iostream>
struct Foo
{
void foo() const { std::cout << "Foo::foo\n"; }
void bar() const { std::cout << "Foo::foo\n"; }
};
struct Biz
{
void old_foo() const { std::cout << "Fiz::old_foo\n"; }
void bar() const { std::cout << "Fiz::foo\n"; }
};
struct Fiz
{
void foo() const { std::cout << "Biz::foo\n"; }
void old_bar() const { std::cout << "Biz::old_foo\n"; }
};
Теперь черта:
template <typename T> struct Dispatch
{
static void foo(T const & x) { x.foo(); }
static void bar(T const & x) { x.bar(); }
};
template <> void Dispatch<Biz>::foo(Biz const & x) { x.old_foo(); }
template <> void Dispatch<Fiz>::bar(Fiz const & x) { x.old_bar(); }
А вот пример использования:
template <typename T> void dispatch(T const & x)
{
Dispatch<T>::foo(x);
Dispatch<T>::bar(x);
}
int main()
{
Foo f;
Biz b;
Fiz c;
dispatch(f);
dispatch(b);
dispatch(c);
}
Прежде всего: подпись всех функций должна быть одинаковой. тогда вы можете установить статический член с адресом функции-члена внутри вашего policy_traits
, так что вы сможете вызвать нужную функцию позже (из вашего Policy
шаблон) с его помощью.
typedef void (*void_memfn_type)();
template<>
struct policy_traits<Widget> {
static void_memfn_type const member_function_name = &Widget::foo;
};
template<>
struct policy_traits<OldWidget> {
static void_memfn_type const member_function_name = &OldWidget::oldFoo;
};
затем:
template<typename Base>
struct Policy<Base> {
// ...
Base* b() { return static_cast<Base*>(this); }
void do(){ b()->policy_traits<Base>::(*member_function_name)(); }
};