c++ - Is this "Tag Dispatching"? -
say have code:
void bara() { } void barb() { } void fooa() { // duplicate code... bara(); // more duplicate code... } void foob() { // duplicate code... barb(); // more duplicate code... } int main() { fooa(); foob(); }
and want remove duplicate code between fooa
, foob
use number of dynamic techniques such passing in bool parameter, passing function pointer or virtual methods if wanted compile time technique this:
struct { }; struct b { }; template<typename tag> void bar(); template<> void bar<a>() { } template<> void bar<b>() { } template<typename tag> void foo() { // duplicate code bar<tag>(); // more duplicate code } int main() { foo<a>(); foo<b>(); }
where have introduced 2 empty "tag" classes indicate bar
use , templated foo
, bar
based on tag class. seems trick. questions:
- does technique have name? example of "tag dispatching"? read tag dispatching different , involves function overloading tag parameter. tag may have come typedef in trait class.
- is there more idomatic compile-time technique of achieving same thing?
edit: possibility use function overloading of bar
instead of template specialization , pass tag class parameter:
struct { }; struct b { }; void bar(a) { } void bar(b) { } template<typename tag> void foo() { // duplicate code bar(tag()); // more duplicate code } int main() { foo<a>(); foo<b>(); }
this isn't tag dispatching. rightly said in question, that'd if used compile time trait of a
, b
distinguish between two, , use select between 2 different overloads.
an example of tag dispatch how std::advance
typically implemented. function's signature is
template< class inputit, class distance > void advance( inputit& it, distance n );
it
can advanced n
positions in single operation if meets requirements of randomaccessiterator. lesser iterators must advance it
in loop. implementation similar following:
namespace detail { template<class inputit, class distance> void advance(inputit& it, distance n, std::random_access_iterator_tag) { += n; } template<class inputit, class distance> void advance(inputit& it, distance n, std::bidirectional_iterator_tag) { if(n < 0) { while(n++) --it; } else { while(n--) ++it; } } template<class inputit, class distance> void advance(inputit& it, distance n, std::input_iterator_tag) { assert(n >= 0); while(n--) ++it; } } template< class inputit, class distance > void advance( inputit& it, distance n ) { detail::advance(it, n, typename std::iterator_traits<inputit>::iterator_category()); }
i don't know of specific name you're doing. it's example of how 1 follow dry principle.
if bar
took instance of a
, b
argument, i'd implement differently. instead of making bar
function template, , providing specializations, i'd let overload resolution job me.
void bar(a const&) { ... } void bar(b const&) { ... }
but since that's not case, providing explicit specializations seems right way this.
Comments
Post a Comment