Suppose I want to write a generic function void f<T>()
, which does one thing if T
is a POD type and another thing if T
is non-POD (or any other arbitrary predicate).
One way to achieve this would be to use a tag-dispatch pattern like the standard library does with iterator categories:
template <bool> struct podness {};
typedef podness<true> pod_tag;
typedef podness<false> non_pod_tag;
template <typename T> void f2(T, pod_tag) { /* POD */ }
template <typename T> void f2(T, non_pod_tag) { /* non-POD */ }
template <typename T>
void f(T x)
{
// Dispatch to f2 based on tag.
f2(x, podness<std::is_pod<T>::value>());
}
An alternative would be to use static member function of partially specialised types:
template <typename T, bool> struct f2;
template <typename T>
struct f2<T, true> { static void f(T) { /* POD */ } };
template <typename T>
struct f2<T, false> { static void f(T) { /* non-POD */ } };
template <typename T>
void f(T x)
{
// Select the correct partially specialised type.
f2<T, std::is_pod<T>::value>::f(x);
}
What are the pros and cons of using one method over the other? Which would you recommend?
I would like tag dispatch because:
It seems tricky to me to add third variant in second example. When you'll want to add, for example non-POD-of-PODs type you'll have to replace bool
in template <typename T, bool> struct f2;
with something other (int
if you like =) ) and replace all struct f2<T, bool-value>
with struct f2<T, another-type-value>
. So that for me the second variant looks hardly extensible. Please correct me if I wrong.