Jansen du Plessis
Jansen du Plessis

Reputation: 235

Passing constant references of primitive types as function arguments

Consider the following function:

template <class T, class Priority>
void MutableQueue<T, Priority>::update(const T& item, const Priority& priority)
{
   ...
}

Would modern x86-64 compilers be smart enough to pass the priority argument by value rather than reference if the priority type could fit within a register?

Upvotes: 8

Views: 875

Answers (3)

EyasSH
EyasSH

Reputation: 3769

As @black mentioned, optimizations are compiler and platform dependent. That said, we typically expect a number of optimizations to happen day-to-day when using a good optimizing compiler. For instance, we count on function inlining, register allocation, converting constant multiplications and divisions to bit-shifts when possible, etc.

To answer your question

Would modern x86-64 compilers be smart enough to pass the priority argument by value rather than reference if the priority type could fit within a register?

I'll simply try it out. See for your self:

This is the code:

template<typename T>
T square(const T& num) {
   return num * num;
}

int sq(int x) {
  return square(x);
}

GCC -O3, -O2, and -O1 reliably perform this optimization.

Clang 3.5.1, on the other hand, does not seem to perform this optimization.

Should you count on such optimization happening? Not always, and not absolutely--the C++ standard says nothing about when an optimization like this could take place. In practice, if you are using GCC, you can 'expect' the optimization to take place.

If you absolutely positively want to ensure that such optimization happens, you will want to use template specialization.

Upvotes: 3

Jarod42
Jarod42

Reputation: 217283

Compiler may do the optimization, but it is not mandatory.

To force to pass the "best" type, you may use boost: http://www.boost.org/doc/libs/1_55_0/libs/utility/call_traits.htm

Replacing const T& (where passing by value is correct) by call_traits<T>::param_type.

So your code may become:

template <class T, class Priority>
void MutableQueue<T, Priority>::update(call_traits<T>::param_type item,
                                       call_traits<Priority>::param_type priority)
{
   ...
}

Upvotes: 3

edmz
edmz

Reputation: 8494

This is totally platform and compiler dependent and so is how the arguments are passed to a function.
These specifics are defined in the ABI of the system the program runs on; some have a large number of registers and therefore use them mainly. Some push them all on the stack. Some mix them together up to N-th parameter.

Again, it is something you cannot rely on; you can check it in a couple of ways, though. The C++ language has no concept of a register.

Upvotes: 0

Related Questions