Zhen
Zhen

Reputation: 4283

How to create a C++ template to pass a value in the best way?

I seem to remember I way to select value-pass or reference-pass of a parameter using the size of the type.

Something like:

void fun( check<A> a ){
    ...
}

Generates or:

void fun( A a ){
    ...
}

or

void fun( A & a ){
    ...
}

Depending of the size of type A and the architecture where you compile the applicacion.

Upvotes: 6

Views: 605

Answers (2)

Rost
Rost

Reputation: 9089

In C++11 you can use std::conditional:

#include <type_traits>

class A { ... };

typedef std::conditional<
   std::is_trivially_copyable<A>::value && sizeof(A) <= sizeof(int),
   A, const A&>::type AParam;

// Direct usage
void f(AParam param);

// Wrap into template class
template <typename T> struct check:
   std::conditional<std::is_arithmetic<T>::value, T, const T&> {};

void f(check<A>::type param);

For C++03 compilers you could use Boost implementation - Boost.TypeTraits library.

As @sehe mentioned there is also Boost.CallTraits library that correctly implements required functionality:

#include <boost/call_traits.hpp>

class A { ... };

void f(boost::call_traits<A>::param_type param);

Upvotes: 13

sehe
sehe

Reputation: 393084

What you describe doesn't directly exist (at least, not standard)

Edit Found what the OP was probably reffering to:

0. Boost Call Traits

call_traits<T>::param_type is likely what the Op had in mind/remembered:

template<typename T> 
   using check = typename boost::call_traits<T>::param_type;

void f(check<A> param);

Defines a type that represents the "best" way to pass a parameter of type T to a function.

Examples

The following table shows the effect that call_traits has on various types, the table assumes that the compiler supports partial specialization: if it doesn't then all types behave in the same way as the entry for "myclass", and call_traits can not be used with reference or array types. enter image description here

You could be referring to two three things, AFAICT:

1. rvalue references

I can imagine you mean that you could optimize for move semantics. E.g.:

struct Demo
{
     Demo(std::string&& tomove) : _s(std::move(tomove)) { }
   private:
     std::string _s;
};

This way,

 std::string a_very_large_string;
 Demo moving(std::move(a_very_large_string)); // prevents a copy

2. Perfect forwarding:

Perfect forwarding is the same principle applied to generic situations:

#include <tuple>
#include <string>
#include <vector>

typedef unsigned int uint;

template <typename... T>
void AnotherDemo(T... args)
{
    std::tuple<T...> perfect(std::forward<T>(args)...); // optimal

    // more code using perfect, passing it by reference etc.
}

int main(int argc, const char *argv[])
{
    AnotherDemo(std::string("moved")); // moved
    AnotherDemo(42);                   // copied

    std::vector<double> v { 1,2,3 };
    AnotherDemo(v);                    // copied
    AnotherDemo(std::move(v));         // moved
}

3. Meta programming:

Building on @Rost's answer, you could use meta programming to achieve this:

E.g. using a template alias:

#include <type_traits>

template<typename T> 
   using check = typename boost::call_traits<T>::param_type;

void f(check<A> param);

Upvotes: 6

Related Questions