Wouter van Ooijen
Wouter van Ooijen

Reputation: 443

Passing a read-only parameter in C++: copy or reference, or

I have a template function, that accepts a read-only parameter of the templated type. This is a library function for various platforms, from 8-bit (AVR8) to 32 bit (Cortex). How to pass this parameter?

template< typename T >
void f( const T p ){ ... }

template< typename T >
void f( const T & p ){ ... }

By value is (probably) more efficient for parameter types that are smaller than a pointer, by reference is (probably) more efficient for parameter types that are larger than a pointer, and/or expensive to copy.

Is there any standard way to abstract this choice, like

template< typename T >
void f( pass_efficiently< T > p ){ ... }

?

Upvotes: 4

Views: 1089

Answers (2)

Joel Filho
Joel Filho

Reputation: 1300

Expanding from Bryan's answer and your additional question, hopefully to make it clear:

You can compose a type trait using Bryan's information and, if you want, the size. For this example, I'm using std::is_trivially_copyable and an implementation-defined maximum size:

template <typename T>
inline constexpr bool is_efficiently_copyable_v =
    std::is_trivially_copyable_v<T> && (sizeof(T) <= magic_size);

Then, you can use this trait to define which function to use with SFINAE (or concepts in C++20), making them mutually exclusive:

template <typename T>
auto f(const T&) -> std::enable_if_t<!is_efficiently_copyable_v<T>>;

template <typename T>
auto f(T) -> std::enable_if_t<is_efficiently_copyable_v<T>>;

(You can also use any other flavor of SFINAE you want)

This way, your function f's interface always receives the parameter in your desired way. Live example: Notice which functions are called in the assembly output.


Just a small side note: GCC generates the same code for const T& and T parameters in all architectures I tested, but Clang doesn't, so beware of that if you just want to go the const reference route. Live example: you may change the parameter type in the main function and between compilers to verify this.

Upvotes: 0

Bryan
Bryan

Reputation: 441

You can use std::is_fundamental to check if the value is a built in type and overload/specialize to pass by value if true.

There are more things to specialize for using the type support library <type_traits> such as is_enum, is_trivially_copyable, is_array and many more. I would recommend checking it out and seeing what works best for you.

Reference link for std::is_fundamental :
https://en.cppreference.com/w/cpp/types/is_fundamental
Reference link for <type_traits>:
https://en.cppreference.com/w/cpp/header/type_traits

Upvotes: 3

Related Questions