Tutorial :How can I use templates to determine the appropriate argument passing method?



Question:

As I understand it, when passing an object to a function that's larger than a register, it's preferable to pass it as a (const) reference, e.g.:

void foo(const std::string& bar)  {      ...  }  

This avoids having to perform a potentially expensive copy of the argument.

However, when passing a type that fits into a register, passing it as a (const) reference is at best redundant, and at worst slower:

void foo(const int& bar)  {      ...  }  

My problem is, I'd like to know how to get the best of both worlds when I'm using a templated class that needs to pass around either type:

template <typename T>  class Foo  {    public:        // Good for complex types, bad for small types      void bar(const T& baz);           // Good for small types, but will needlessly copy complex types      void bar2(T baz);               };  

Is there a template decision method that allows me to pick the correct type? Something that would let me do,

void bar(const_nocopy<T>::type baz);  

that would pick the better method depending on the type?


Edit:

After a fair amount of timed tests, the difference between the two calling times is different, but very small. The solution is probably a dubious micro-optimization for my situation. Still, TMP is an interesting mental exercise.


Solution:1

Use Boost.CallTraits:

#include <boost/call_traits.hpp>    template <typename T>  void most_efficient( boost::call_traits<T>::param_type t ) {      // use 't'  }  


Solution:2

If variable copy time is significant, the compiler will likely inline that instance of a template anyway, and the const reference thing will be just as efficient.

Technically you already gave yourself an answer.

Just specialize the no_copy<T> template for all the nocopy types.

template <class T> struct no_copy { typedef const T& type; };    template <> struct no_copy<int> { typedef int type; };  


Solution:3

The only solution I can think of is using a macro to generate a specialized template version for smaller classes.


Solution:4

First: Use const & - if the implementation is to large to be inlined, the cosnt & vs. argument doesn't make much of a difference anymore.

Second: This is the best I could come up with. Doesn't work correctly, because the compiler cannot deduce the argument type

template <typename T, bool UseRef>   struct ArgTypeProvider {};    template <typename T>  struct ArgTypeProvider<T, true>  {     typedef T const & ArgType;  };    template <typename T>  struct ArgTypeProvider<T, false>  {     typedef T ArgType;  };    template <typename T>  struct ArgTypeProvider2 : public ArgTypeProvider<T, (sizeof(T)>sizeof(long)) >  {  };    // ----- example function  template <typename T>  void Foo(typename ArgTypeProvider2<T>::ArgType arg)  {     cout << arg;  }    // ----- use  std::string s="fdsfsfsd";  // doesn't work :-(  // Foo(7);  // Foo(s);    // works :-)  Foo<int>(7);  Foo<std::string>(s);  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »