简体   繁体   中英

C++11 auto type deduction from arithmetic operation on int& and long

I must be misunderstanding how auto c++11 and later resolves types. I have the following code:

void foo(int& x)
{
    ++x;
}

int main()
{
    int i = 2;
    int& ir = i;
    long L = 5;
    auto a = ir/L;
    foo(a);

    return 0;
}

This results in the compiler error:

test.cpp: In function 'int main()':

test.cpp:12:10: error: invalid initialization of non-const reference
of type ‘int&’ from an rvalue of type ‘int’
     foo(a);
          ^

test.cpp:1:6: note:   initializing argument 1 of ‘void foo(int&)’
 void foo(int& x)
      ^~~

However, replacing auto with int ( int a = ir/L; ) compiles fine and gives the expected result ( a == 0 before the call to foo() , and a == 1 after). After playing around with the code and seeing various error messages, I think auto is deduced to long int& . Defining the functions void bar(int x) and void bar(const int& x) results in the error message: call of overloaded 'bar(long int&)' is ambiguous .

Correction from comments:

I don't understand how auto x = [int&]/[int] result in an lvalue that can be passed by non-const ref while auto x = [int&]/[long] results in an rvalue that cannot.

The result of ir/L is long . For arithmetic operator , when binary operators have different types, the result produced will be of the common type; between int and long it would be long .

So auto a = ir/L; , the type of a is long . It can't be passed to foo(int&) because you can't bind lvalue reference to non-const with different type.

On the other hand, given the type of L is int , then for auto a = ir/L; , the type of a will be int , then everything is fine.

About the "the rvalue part of the error", when you pass a long to foo(int&) , firstly the compiler will try to convert it to int , which is a temporary (ie an rvalue) and can't be bound to lvalue reference to non-const.

long could be implicitly converted to int , and temporary could be bound to lvalue reference to const, so passing a long variable to both bar(int x) and bar(const int&) is fine.

BTW: When you write int a = ir/L; , the result of type long is implicitly converted to int . So you'll get an int then it's fine to pass it to foo(int&) .

The fact that you've used auto is not relevant.

a is a long type, due to the rules of argument promotion.

Because foo takes the parameter by reference , compilation fails since an int& cannot bind to a long type (even if they are the same size and have the same complement representation).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM