Search code examples
c++c++11templatesdecltypetype-deduction

Use of decltype Gives warning Reference to Local Variable


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.

Check out the code here


Solution

  • 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&.