Функции-члены & quot; имя & quot; в классе черт? (универсальный адаптер)

Я реализовал Политику, используя 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(); }
};

Надеемся, что есть лучший способ добиться этого.

1

Решение

Вот пример того, как специализируется выборочно. Сначала несколько примеров классов:

#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);
}
2

Другие решения

Прежде всего: подпись всех функций должна быть одинаковой. тогда вы можете установить статический член с адресом функции-члена внутри вашего 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)(); }
};
3