Question

I need a way to decide whether to pass an arbitrary type T by copy or by const-reference (e.g., if T is small enough then copy if, otherwise pass it by const-reference). To avoid reinventing the wheel, I tried out Boost Call Traits.

As expected, primitive types are passed by value, and complex types like std::string are passed by reference. However, tiny non-primitive types are also passed by reference, e.g., std::pair<char, char>, which does not seem to be the best choice. I assumed that everything up to sizeof(void*) would be passed by value.

Generally, the Boost libraries are of high quality, so maybe I am missing something.

Here is my test code:

#include <iostream>
#include <type_traits>
#include <tuple>
#include <boost/call_traits.hpp>

template <typename TYPE>
void test(const char* type_name)
{
  typedef typename boost::call_traits<TYPE>::param_type T;  
  if(std::is_reference<T>::value)        
    std::cout << type_name << " is passed by reference (sizeof=" << sizeof(TYPE) << ")\n"; 
  else 
    std::cout << type_name << " is passed by value (sizeof=" << sizeof(TYPE) << ")\n"; 
}

int main()
{
  test<short>("short");
  test<int>("int");
  test<double>("double");
  test<std::string>("std::string");
  test<long long>("long long");
  test<std::pair<int, int>>("std::pair<int, int>");
  test<std::pair<short, short>>("std::pair<short, short>");
  test<std::pair<char, char>>("std::pair<char, char>");
  test<std::tuple<char, char>>("std::tuple<char, char>");
  test<std::tuple<char, char, char, char>>("std::tuple<char, char, char, char>");
  test<std::pair<long long, long long>>("std::pair<long long, long long>");
  return 0;
}

And here are the results (Boost 1.50, g++ 4.7.2):

short is passed by value (sizeof=2)
int is passed by value (sizeof=4)
double is passed by value (sizeof=8)
std::string is passed by reference (sizeof=8)
long long is passed by value (sizeof=8)
std::pair<int, int> is passed by reference (sizeof=8)
std::pair<short, short> is passed by reference (sizeof=4)
std::pair<char, char> is passed by reference (sizeof=2)
std::tuple<char, char> is passed by reference (sizeof=2)
std::tuple<char, char, char, char> is passed by reference (sizeof=4)
std::pair<long long, long long> is passed by reference (sizeof=16)
Was it helpful?

Solution

Call Traits is a generic library and must work with any user-defined types. To decide whether it is faster to pass an arbitrary type by value requires extra knowledge which is beyond the scope of the library. So, the conservative approach of always passing by value when in doubt, is reasonable.

Although it should be possible to extend it to improve the support for commonly used STL types (e.g., std::pair, std::tuple, std::array), there is no generic way to do so.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top