isocpp / isocpp/CppCoreGuidelines
T.65 Is tag dispatch antiquated?
Nobody has claimed this yet.
- Dominant language
- CSS
- Stars
- 45.3k
- Forks
- 5.6k
- PR merge metrics
- No merged PRs in 30d
Description
In modern C++, I don't see a reason to use tag dispatch in the example of T.65:
Tag Dispatch
struct pod_tag {};
struct non_pod_tag {};
template<class T> struct copy_trait { using tag = non_pod_tag; }; // T is not "plain old data"
template<> struct copy_trait<int> { using tag = pod_tag; }; // int is "plain old data"
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 loop calling copy constructors
}
template<class Iter>
Out copy(Iter first, Iter last, Iter out)
{
return copy_helper(first, last, out, typename copy_trait<Value_type<Iter>>::tag{})
}
constepxr if (Strawman)
struct pod_tag {};
struct non_pod_tag {};
template<class T> struct copy_trait { using tag = non_pod_tag; }; // T is not "plain old data"
template<> struct copy_trait<int> { using tag = pod_tag; }; // int is "plain old data"
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 loop calling copy constructors
}
template<class Iter>
Out copy(Iter first, Iter last, Iter out)
{
// note: at least in this example, we could get rid of the tag completely and have a condition:
// IsPod_v<ValueType<Iter>>
//
// if constexpr gets a bit annoying with more than three cases, but it is extremely rare that you
// would dispatch to more than two alternative implementations
if constexpr (std::is_same_v<pod_tag, typename copy_trait<ValueType<Iter>>::tag>) {
trivially_copy(first, last, out);
}
else {
algo_copy(first, last, out);
}
}
Even if you are using a tag, you can just as well check the tag with if constexpr and dispatch to functions with distinct names. In my opinion, uses of tag dispatch like above are antiquated and should no longer be recommended.
The second version:
- probably compiles faster, because we reduce the sizes of overload sets everywhere
- 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. In C++20 you might also just create overloads with constraints like template <pod_type T>, which also seems easier and cleaner than tag dispatch.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing guideline T.65 and the tag-dispatch example quoted in this issue, then compare it with the proposed C++17 if constexpr approach. Check the comment thread for context and decide whether the guideline should be revised; done means the recommendation and example accurately reflect the project's settled position.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100