4

This is a follow up questions from Static polymorphism in C++

  • When should I prefer duck typing?

  • When should I prefer CRTP?

  • Are there any best practices?

It would boil down to this:

template<typename T>
void print_renderer(const renderer<T> &r){
    r.get();
}

vs

template<typename T>
void print_renderer(const T &r){
    static_assert(is_renderer<T>,"Not a renderer");
    r.get();
}

What I have observed so far:

  • CRTP is not as nice to use as run-time polymorphism. To create an polymorphic interface someone has just to use virtual and override. Both of these keywords can't be used with CTRP. If I I have a typo in my implementation it will trigger a run-time error. (Maybe this can be prevented)

  • Duck typing is really simple but it may confuse my clients. If they don't have access to the source code and they have to use void print_renderer(T r) vs void print_renderer(renderer<T> r) I think CRTP is much clearer.

  • Duck typing does have a maintaining cost. In my previous question I created an open_gl and direct_draw implementation for my renderer. If I wanted to add another renderer for example open_gl_es, I would also have to change my is_renderer<T> function. But I don't think it would be too bad.

Community
  • 1
  • 1
Maik Klein
  • 15,548
  • 27
  • 101
  • 197
  • 2
    Don't use duct tape - weld it up. – Martin James Aug 29 '14 at 10:56
  • Your example isn't CRTP. – Simple Aug 29 '14 at 10:57
  • @Simple I reused the code from my initial SO question that I have linked at the top. Should I copy the code into this one? – Maik Klein Aug 29 '14 at 10:59
  • 1
    What you linked uses CRTP, yeah, but the bit you pasted isn't the CRTP bit. The CRTP bit is the `struct open_gl : public renderer`. Duck typing and CRTP are orthogonal concepts. – Simple Aug 29 '14 at 11:00
  • Yes but I use it in `print_renderer`. With CTRP I can make the type explicit in the parameter and that's what my question is about. – Maik Klein Aug 29 '14 at 11:03
  • 1
    Also note that your example and the code you linked to is actually incorrect. `template void print_renderer(renderer r)` as well as `T r` will cause slicing. You should take by reference, as always when dealing with polymorphism. – Simple Aug 29 '14 at 11:03
  • Thanks for the catch, just copied it from my old question. – Maik Klein Aug 29 '14 at 11:05

1 Answers1

2

Your first code sample where you take a renderer<T> by reference should be preferred. What you are doing in your second code sample is basically reimplementing overload resolution rules yourself.

Simple
  • 13,992
  • 2
  • 47
  • 47