Вопрос

When writing a template function like:

template<class T> void print(T const & collection)

When looping through the collection and dereferencing the iterator everything works right if you have something like vector<int> unless you change it to vector<int*>. What's the best way to deal with the differences in a single template function whilst not duplicating code?

Это было полезно?

Решение

I would write a single template function do_print that delegates to a class template printer. The class template is a function object that does the pretty printing, and that you partially specialize for T* by simply calling the pretty print version on *t.

So there is no duplication of the pretty printing code and a minor inconvenience for writing two lightweight implementation classes (these get optimized away by any modern compiler, so there is no runtime overhead).

I prefer this solution over SFINAE tricks because partial class specialization gives you much more control (and much better error messages) than function overloading tricks. It's also recommended by the Alexandrescu & Sutter Coding Standards.

BTW, this code will also work for T** because the specialization for T* delegates to the code for T. So T** is send to T* and finally to T. In fact, arbitrary levels of indirection get reduced to printing the elements pointed to by pointers.

#include <iostream>
#include <vector>

namespace detail {

template<typename T>
struct printer
{
   void operator()(T const& t) 
   { 
      std::cout << t; // your pretty print code here
   }  
};

template<typename T>
struct printer<T*>
{
   void operator()(T const* t) 
   { 
      printer<T>()(*t); // delegate to printing elements (no duplication of prettty print)
   }
};

}

template<typename T>
void do_print(T const& t)
{
   detail::printer<T>()(t);
}

template<typename C>
void print(C const& collection)
{
   for(auto&& c: collection) 
      do_print(c);
   std::cout << "\n";
}

int main()
{
   int a = 1;
   int b = 2;

   auto c = &a;
   auto d = &b;

   std::vector<int> v1 { a, b };
   std::vector<int*> v2 { c, d };
   std::vector<int**> v3 { &c, &d };

   print(v1);
   print(v2);
   print(v3);
}

Output on Live Work Space

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top