5

The CppCoreGuidelines contain the following:

T.65: Use tag dispatch to provide alternative implementations of a function

[...]

Example
struct pod_tag {};
struct non_pod_tag {};

template<class T> struct copy_trait { using tag = non_pod_tag; };

template<> struct copy_trait<int> { using tag = pod_tag; };

template<class Iter>
Out copy_helper(Iter first, Iter last, Iter out, pod_tag) { /* use memmove */ }

template<class Iter>
Out copy_helper(Iter first, Iter last, Iter out, non_pod_tag) { /* use copy constr. */ }

template<class Iter>
Out copy(Iter first, Iter last, Iter out)
{
    return copy_helper(first, last, out, typename copy_trait<iter_value_t<Iter>>::tag{})
}

I feel like this design is extremely antiquated, and modern C++ has better tools to offer as a replacement:

Alternative - constexpr if dispatch

// prefer boolean traits over tags
template<class T> struct is_pod: std::false_type {};

template<> struct is_pod<int> : std::true_type {};

template<class Iter>
Out trivially_copy(Iter first, Iter last, Iter out) { /* use memmove */ }

template<class Iter>
Out algo_copy(Iter first, Iter last, Iter out) { /* use copy constructor */ }

template<class Iter>
Out copy(Iter first, Iter last, Iter out)
{
    if constexpr (is_pod<ValueType<Iter>>::value) {
        trivially_copy(first, last, out);
    }
    else {
        algo_copy(first, last, out);
    }
}

This alternative:

  • probably compiles faster, because we reduce the sizes of overload sets
  • makes it possible to inline short implementations into the branches when needed
    • (this would have been impossible before C++17 and would have needed tag dispatch or a runtime if statement)
  • has functions with meaningful names, which conveys intent more easily than overload sets with tag parameters
  • reduces the sizes of the helper function signatures

I fail to see any legitimate reason why you would use tag dispatch in C++17 here. Am I missing something, or is it an antiquated design pattern that serves no purpose in this case?


Note: the guidelines also offer C++20 constraints as an alternative, but they have a slightly different purpose and C++20 isn't as widely supported yet, so I don't want to discuss them in this question.

1 Answer 1

1

When evaluating the approaches, keep this in mind:

  1. The Tag dispatch example suffers from being contrived, trivial and self-contained for illustration purposes.

    In the cases it is most appropriate, your code either offers the tags for extension, or just consumes them, cutting the code in half.

  2. The explicit dispatch by constexpr suffers from limited extensibility, at least without rewriting the dispatcher.

Thus, if it is a one-of dispatch, constexpr is certainly simpler, shorter, and faster to compile.
On the other hand, if you repeatedy dispatch on the same criteria, you are consuming the tags, or it is an extension point, tag-dispatch will be simpler and less repetitive.

Also, the types are a critical part of a functions signature and often carry important information. The name itself only has to do it all in C and the like.

2
  • "Also, the types are a critical part of a functions signature and often carry important information." if we're using the tag dispatch to provide alternative implementations, then by design, we just repeat the same types everywhere. I don't see how that is an argument against if constexpr. I admit that it's slightly easier to add one more overload that gets dispatched, because the dispatching code always looks the same. However, it's very rare that you would do this refactoring. At least for things like iterator tags, the tags never change. Commented Jul 1, 2023 at 11:53
  • @JanSchultke Just to undermine my own point of leveraging existing tag-dispatch-machinery, there are major problems with the iterator-tags, as they amalgamate a few different dimensions of the design which have been proven to be not actually that dependent. Quite a mess there. Commented Jul 1, 2023 at 13:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.