3

I am trying to understand better when decay or not a type

#include <type_traits>
 

template <typename T1, typename T2> auto max_test(T1 a, T2 b) -> typename std::decay<decltype(a > b ? a: b)>::type {
    return a < b ? a : b;
}

template <typename T1, typename T2> auto max_test_r(T1 a, T2 b) -> decltype(a > b ? a: b) {
    return a < b ? a : b;
}

Which is the most correct version and why? Should i avoid using decays or when should i use them?

The second if flawed, thanks to Adam for the answer. The problem is that you are decltyping an lvalue.

jozoppi
  • 31
  • 4

2 Answers2

4

If a and b are the same literal type, your decay-less one returns a dangling reference.

Your decay one does not.

There are going to be a myriad of other less important differences, but that bug is pretty big.

Decay does specific things. When you should use it is when either you want those things to happen, or when you have a type you need to store a copy of as a value.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Got it, It has taken me a while. it is because the operator decltype in the function definition return a reference from an lvalue, so we return a reference and we need to decay it, correct? It looks like we've the power to shoot in our feet. So for the time being in most simple case just auto is enough and we're fine. – jozoppi Oct 16 '21 at 12:41
  • @jozoppi Lifetime is hard, use values unless you want to do the work. – Yakk - Adam Nevraumont Oct 16 '21 at 13:20
  • Yes, i'll do the work. It ain't about how hard you hit. It's about how hard you can get hit and keep moving forward (cit.) . – jozoppi Oct 16 '21 at 15:10
2

Which is the most correct version and why?

The correct one is the second one, without the std::decay as you want to return the same type of either a or b. That means either T1 or T2.


Should I avoid using std::decays or when should I use them?

This has been better explained in this post: What is std::decay and when it should be used?

That being said, in C++17 you only need something without the trailing return.

template <typename T1, typename T2> 
auto max_test_r(T1 a, T2 b) 
{
    return a > b ? a : b;
}

You use std::decay if you want the actual type without the const- volatile qualifiers.

JeJo
  • 30,635
  • 6
  • 49
  • 88