up:: Cpp
source:: C++ のダブルアンパサンド | Delft スタック
source:: 7分でわかる右辺値参照 - Qiita

二個ついてるやつは、lvalueとrvalueを理解しないといけない。
lは左辺値であり、メモリに書き込まれる値。
rは右辺値であり、メモリに書き込まれない値。

int number = 10;

例えばこのコードがあった場合、numberがlvalueで10がrvalue。
rvalueはメモリに無いので&を付けてもアドレスはとれない。

//int *ptr_10 = &10;
//(error) expression must be an lvalue

で、&一個参照はlvalueを取り、&二個参照はrvalueを取れる。扱いとしては型と同じ。
つまり、&&参照を引数にした関数だと、素で打ち込んだ数値でエラーにならない。

//single ampersand sign is used to refer lvalue
int add(int &a, int &b)
{
    return a+b;
}
 
//double ampersand sign is used to refer rvalue
 
int add_(int &&a, int &&b)
{
    return a+b;
}
int main()
{
    //here we pass lvalue to the function
    int num1=10;
    int num2=30;
    int sum = add(num1,num2);
    cout<<sum<<endl;
    //it will give the error if we pass the rvalues to that function
    // int sum_1= add(10,30);
    //(error) initial value of reference to non-const must be an lvalue
 
 
    //c++11 provides the facility of passing rvalues by using double ampersand sign
     int sum_1= add_(10,30);
     cout<<endl;
}

より詳しい話。
&&とすると、rvalueを参照できる値が作れる。これは右辺値参照と呼ばれる。要は&&は変数を入れられない
反対に型名&はlvalue参照であり、左辺値参照。rvalueが入らない。

……が、constの左辺値参照はrvalueが入る。
分かるようなわからんような。
一応ここの5.にちょっとだけ書いてる。

int main()
{
  int x = 0;
 
  // 左辺値参照
  int& lvalue_ref_1 = x;              // OK
  // int& lvalue_ref_2 = 0;           // Error 右辺値を左辺値参照で束縛している
 
  // 右辺値参照
  // int&& rvalue_ref_1 = x;          // Error 左辺値を右辺値参照で束縛している
  int&& rvalue_ref_2 = 0;             // OK
 
  // const左辺値参照
  const int& const_lvalue_ref_1 = x;    // OK
  const int& const_lvalue_ref_2 = 0;    // OK const左辺値参照は右辺値を束縛できる
}

なお参照の変数自身は左辺値なので、右辺値参照も左辺値。

int main()
{
  // xの型は int&& である
  // xは左辺値=xは実体を持ち名前のあるオブジェクト
  int&& x = 1;
 
  // xは左辺値なので右辺値参照できない!
  //int&& y = x; // Error!
}

これ何のためにあるのかというと、関数に引数のコピーコストをかけないため。
わざわざ一時で消滅する値をコピーするのは無駄。言い換えると、右辺値参照は消してもいい値を表現するために存在する。

ちなみに、実際に消してもいい値を消してはいけない値に受け渡す関数がstd::move()。コピーでは重いときなんかに使うらしい。

あれ? この説明だと右辺値しか受けられない使いにくい関数が出来るのでは?
と思ったらちゃんとその辺も構文がある。
ユニバーサル参照