1

I have implemented a Policy using the CRTP. The policy requires the Base class to have a function called foo:

template<typename Base>
struct Policy<Base> {
  // ...
  Base* b(){ return static_cast<Base*>(this); }
  void do(){ b()->foo(); }
};

I have one class called Widget that uses my policy. Widget implements foo and everything is fine:

struct Widget : Policy<Widget> {
  // ...
  void foo();
};

The problem: I also have a type called OldWidget that implements the functionality of foo in a function named oldFoo:

struct OldWidget : Policy<OldWidget> {
  // ...
  void oldFoo();
};

I don't want to modify OldWidget (besides extending it with the policy). I don't want to use an AdaptedOldWidget:

struct AdaptedOldWidget : OldWidget, Policy<AdaptedOldWidget> {
  void foo(){ oldFoo(); }
};

The best would be to extend my existing policy_traits class to something like:

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;
};

Such that I can implement the Policy like this:

template<typename Base>
struct Policy<Base> {
  // ...
  Base* b() { return static_cast<Base*>(this); }
  void do(){ b()->policy_traits<Base>::member_function_name(); }
};

Is there away to achieve something like this in C++?

Proposed solution: I could do the following:

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(); }
};

There must be hopefully a better easier way to achieve this.

gnzlbg
  • 7,135
  • 5
  • 53
  • 106
  • 1
    Can't you just specialize the policy for `OldWidget`? (Otherwise, there's an example of a trait that detects the presence of member functions in [the pretty printer code](http://stackoverflow.com/questions/4850473/pretty-print-c-stl-containers).) – Kerrek SB Jan 22 '13 at 08:50
  • @KerrekSB wouldn't I need to duplicate a lot of the policy code? I would like to reuse everything in the policy, just replace the function name to something dependent on the type. I'll check out the pretty printer code, thanks! – gnzlbg Jan 22 '13 at 08:52
  • Just specialize the dispatch (e.g. make another, dedicated "dispatch" policy). – Kerrek SB Jan 22 '13 at 09:03
  • @KerrekSB like the Policy_Member_Traits policy I just proposed? Isn't there a better way? It's not very clean, and I would need a 1) type_traits class, and 2) a member_function "traits" class, per type... It's just weird. – gnzlbg Jan 22 '13 at 09:05
  • 1
    Well, in your ill-named `void do()` (keyword alert!), you would say `DispatchPolicy::dispatch_foo(b);` or something like that, and the `DispatchPolicy` template would only contain the relevant function definitions, specializing individual cases. – Kerrek SB Jan 22 '13 at 09:12
  • @KerrekSB seems reasonable! keyword indeed! – gnzlbg Jan 22 '13 at 09:14

2 Answers2

3

first of all: signature of all functions must be the same. then you may set a static member w/ member-function address inside of your policy_traits, so you'll be able to call desired function later (from your Policy template) using it.

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;
};

then:

template<typename Base>
struct Policy<Base> {
  // ...
  Base* b() { return static_cast<Base*>(this); }
  void do(){ b()->policy_traits<Base>::(*member_function_name)(); }
};
zaufi
  • 6,811
  • 26
  • 34
  • This looks nice but widget is not a complete type until *after* the policy has been instantiated and thus I cannot take a pointer to member function *before* instantiating it. Have you tried this? – gnzlbg Jan 22 '13 at 09:29
2

Here's an example how specializing selectively. First, some example classes:

#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"; }
};

Now the trait:

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(); }

And here's a usage example:

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);
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • This seems to work! Should I use a reference or a pointer? Im calling dispatch from the CRTP so with the reference is something like `dispatch(*b())` and the objects are pretty large. – gnzlbg Jan 22 '13 at 09:43
  • Actually I can include the dispatch in the trait, so I'll mark the question as answered. – gnzlbg Jan 22 '13 at 10:33