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.
CodePudding user response:
You can't rely on warnings. You have to rely on yourself to not write dangerous code.
Returning (b < a ? a:b)
from a function that returns a reference is dangerous: whichever of a
and b
ends up being returned, the result will still be a dangling reference. In your case, the compiler was not able to catch this, because the expression you returned was too complicated and whatever part of the compiler generates the warning is not sophisticated enough to figure out that this return
statement will yield a danging reference.
The only foolproof solution is to not write code like this. Furthermore, you need to stop using "whether or not the compiler issues a warning" as a way to experimentally learn the rules of the language. It is too unreliable.
CodePudding user response:
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?
Understanding the construct where the bug appeared
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&
.