Const和非const引用绑定

kun*_*nir 5 c++ compiler-errors

void swap(int& a, int& b) {}

void copy(int& a, const int& b) {}

int main() {
   int a=1;
   unsigned b=2;

   swap(a, b);
   copy(a, b);
}
Run Code Online (Sandbox Code Playgroud)

C++语言,g ++编译器.

请告诉我为什么copy -function调用中没有编译错误,但是在swap -function触发器中invalid initialization of reference of type ‘int&’ from expression of type ‘unsigned int’.

对不起,我的英语不好.

Pix*_*ist 4

短篇故事

首先 - 将具有U限定条件的类型表达式的引用绑定到具有限定条件cv2的类型引用的规则 L :Tcv1

的引用cv1 T可以通过类型的表达式来初始化cv2 U

  • 如果引用是左值引用且初始化表达式

    • cv1 T是一个左值并且与, 或引用兼容cv2 U
    • 有一个类类型 [...]。
  • 否则,cv1应为const或该引用应为右值引用。

cv1 T引用兼容cv2 UifT与 相同类型U(或 的基数U)并且 ifcv1等于cv2(或更大)。

不幸的是(或者幸运的是?!;))具有非常量左值引用参数的函数不能使用非引用兼容类型的左值调用(或者在类类型没有将传递的参数可行地转换为参考兼容类型)。

详细

让我们考虑一个采用整数引用的函数和具有常量整数引用参数的第二个函数。

void doSomething (int & x)
{
  // do some READ & WRITE stuff with x
  x = x+5;
}

int doSomethingElse (int const & x)
{
  // do some READ ONLY stuffwith x
  return 3*x;
}
Run Code Online (Sandbox Code Playgroud)

让我们看一下一个有符号值和另一个无符号值:

 int a = 1;
 unsigned int b = 2;
Run Code Online (Sandbox Code Playgroud)

现在我们将int命名传递adoSomething()

 // works since x of doSomething can bind to a
 doSomething(a);

 // let's try to expand/"inline" what is happening
 {
   int & x = a;
   x = 5;
 }
Run Code Online (Sandbox Code Playgroud)

这里没有魔法,引用x绑定到a并设置为 5(因此也是 a)。美好的。

现在我们尝试传递b给同一个函数。但 ...

   // ... it doesn't work/compile since
   // unsigned int is not reference compatible to int
   doSomething(b); // compile error here

   // what's going on here
   {
     int & x = b; // unsigned value cannot bind to a non-const lvalue reference!
                  // compile error here
     x = 5;
   }
Run Code Online (Sandbox Code Playgroud)

在这里我们开始遇到麻烦,调用doSomethingwithb将无法编译。

现在让我们看看 const 引用函数。通过a显然不再有问题。const int 引用绑定到一个int值。

int c = doSomethingElse(a);
 
// let's do some naive inlining again
int c;
{
  int const & x = a;
  c = 3*x;
}    
Run Code Online (Sandbox Code Playgroud)

嗯,看起来还不错。c3*a

b现在,如果我们传递给该函数会发生什么?该标准规定,在这种情况下,cv1 T将使用复制初始化规则从初始化表达式创建并初始化类型的临时值。

int d = doSomethingElse(b);

// expanding this to:
int d;
{
  int temp = b; // implicit conversion, not really an lvalue!
  int const & x = temp;
  d = 3*x;
} 
Run Code Online (Sandbox Code Playgroud)