I am trying to understand how decltype
works in C++ and so going through examples. Just when i thought i understood what it means, i tried to create examples to confirm that and i got something that i cannot understand. The example is as follows:
#include <iostream>
template<typename T>
auto func2(T a, T b) -> decltype(b < a ? a:b)
{
//return a;//this gives warning of reference to local variable
//return b;//this gives warning of reference to local variable
return (b < a ? a:b);//this does not give warning of reference to local variable
}
int main()
{
std::cout << "Hello World" << std::endl;
int b = func2(4,3);
return 0;
}
As shown in the above code when i use the statement return a;
or return b;
i get a warning saying reference to local variable which is because we should never pass reference or pointers to local variable to outside their scope. But what i don't understand is that why are we not getting the same warning when i use return (b < a ? a:b);
.
My thinking is that decltype(b < a ? a:b)
should result in int&
. And so when i write return (b < a ? a:b);
a reference to local a
or b
should be returned depending on whether which one is greater and we should get the warning.
But what i don't understand is that why are we not getting the same warning when i use return (b < a ? a:b);
How clever compiler warnings can be is entirely up to the compiler vendor; see e.g.
and when you catch a bug through a compiler warning, the general lesson should arguably be
Phew, glad my compiler caught that one: I need to understand this construct better
as opposed to
Why didn't the compiler also catch my other bug?
I am trying to understand how decltype works in C++ and so going through examples. Just when i thought i understood what it means, i tried to create examples to confirm that and i got something that i cannot understand.
For completeness, [expr.cond]/5 covers the resulting type of a ternary conditional-expression its last two operands are both glvalues of the same type and value category:
If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category and it is a bit-field if the second or the third operand is a bit-field, or if both are bit-fields.
Meaning in your example, the type of the result (for function arguments deducing the template parameter to int
) is int
:
void f(int x) {
auto result = false ? x : x;
static_assert(std::is_same_v<decltype(r), int>);
}
[dcl.type.decltype]/1 governs the rules for decltype
, and particularly [dcl.type.decltype]/1.5 applies here:
For an expression E, the type denoted by decltype(E) is defined as follows:
- [...]
- /1.5 otherwise, if E is an lvalue, decltype(E) is T&, where T is the type of E;
Thus, in the particular (deduced) specialization func2<int>(...)
of your example, the return type is deduced to int&
.