Monday, November 28, 2011

Understanding C++ Traits

Suppose we have a function that does this
if class is foo, use a new implementation
else use an old implementation
There are many ways to achieve this. The naive way is as shown below.
if (instance.type() == "foo") {
    instance.new_impl();
} else {
    instance.old_impl();
}
Another way is to use a runtime polymorphism as shown below.
class foobar_base {
public:
    virtual ~foobar_base() {}
    virtual void impl() = 0;
}

class foo : public foobar_base {
public:
    virtual ~foo() {}
    void impl() { 
        cout << "New implementation" << endl;
    }
};

class bar : public foobar_base {
public:
    virtual ~bar() {}
    void impl() {
        cout << "Old implementation" << endl;
    }
}

void do_something(const foobar_base& fb) {
    fb.impl();
}
If we need to avoid any runtime type check and use a compile-time type check, we can achieve it by leveraging on the C++ templates and use C++ traits to store the type information as shown on the example below.
#include <iostream>
using namespace std;

template<typename T>
struct impl_traits {
    static const bool value = false;
};

template<typename T>
void do_something() {
    if (impl_traits<T>::value) {
        T::new_impl();
    } else {
        T::old_impl();
    }
};

class foo {
public:
    static void old_impl() {
        cout << "[foo] Old implementation" << endl;
    }

    static void new_impl() {
        cout << "[foo] New implementation" << endl;
    }
};

class bar {
public:
    static void old_impl() {
        cout << "[bar] Old implementation" << endl;
    }

    static void new_impl() {
        cout << "[bar] New implementation" << endl;
    }
};

template<>
struct impl_traits<foo> {
    static const bool value = true;
};


int main() {
    do_something<foo>();
    do_something<bar>();

    return 0;
}
The output is
[foo] New implementation
[bar] Old implementation

No comments:

Post a Comment