1

Suppose I want to implement some simple mathematical function; for example suppose it's a reimplementation of (C++17's) std::clamp: This function takes a number, a lower bound and an upper bound, and sets the number to one of those bounds if its out of the range they define. If it's a concrete numeric type, say int, I would write:

constexpr int clamp(int x, int lower_bound, int upper_bound)
{
    return x < lower_bound ? lower_bound : ( upper_bound < x ? upper_bound : x );
}

but if it's a template, I see that the sample implementation which is probably what the standard is going to have uses const&'s rather than values. So, making things simpler for quoting, something like:

template <typename T>
constexpr T clip(const T& x, const T& lower_bound, const T& upper_bound)
{
    return x < lower_bound ? lower_bound : ( upper_bound < x ? upper_bound : x );
}

My questions are:

  • Is there any benefit to taking a const reference, for T's which are simple numeric types?
  • Ditto, for types which are some abstract thing wrapping a single number as a data member (e.g. a std::chrono duration)?
  • Why is it (and is it at all) a better idea to take a const& then a value in the general case of any relatively-simple, (constexpr?), side-effect-free math-ish function?

Notes:

  • I realize taking a const& might start making sense when you have, say, some kind of k-dimensional vector type, or boost::rationals and other numeric-like types; but even then, wouldn't a compiler optimize the copying away?
  • I'm not asking about any arbitrary C++ function and whether it should just take its parameters by value, that would be a bad idea obviously.
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • They could not be _simple numeric types_. They could be _types that behave like numbers_. You could want not to copy them after all. Moreover, a const reference binds to a temporary and sometimes it's useful. – skypjack Oct 12 '16 at 21:29
  • `std::complex` might be an actual example of type in C++ standard for which `const T&` would be better than just `T`. – Zereges Oct 12 '16 at 21:40
  • @Zereges: Again, why? Wouldn't the compiler optimize the difference away? – einpoklum Oct 12 '16 at 21:44
  • @einpoklum It could of course as with any other type for your given function – Zereges Oct 12 '16 at 22:10
  • @Zereges: Not with types having data on the heap I'd guess. – einpoklum Oct 13 '16 at 08:27

2 Answers2

3
  • Is there any benefit to taking a const reference, for T's which are simple numeric types?

No.

  • Ditto, for types which are some abstract thing wrapping a single number as a data member (e.g. a std::chrono duration)?

No.

  • Why is it (and is it at all) a better idea to take a const& than a value in the general case of any relatively-simple, (constexpr?), side-effect-free math-ish function?

Imagine a bigint type that uses dynamic allocation; copying such a type is expensive.

  • Wouldn't a compiler optimize the copying away?

Only if it can prove that copying the value have no side effect, which is hard to do unless all the code involved is visible to the compiler. (So, if your bigint uses, say, GMP, you are out of luck.)

T.C.
  • 133,968
  • 17
  • 288
  • 421
2

Is there any benefit to taking a const reference, for T's which are simple numeric types?

No, I don't think so but there are no penalties either.

Ditto, for types which are some abstract thing wrapping a single number as a data member (e.g. a std::chrono duration)?

Ditto.

Why is it (and is it at all) a better idea to take a const& then a value in the general case?

The standard library algorithms are designed not just for fundamental types but also for user defined types, which may not be cheap to copy. For those types, using a const& avoids the penalties of copying while not hurting the usages for fundamental types.

R Sahu
  • 204,454
  • 14
  • 159
  • 270