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.