web-dev-qa-db-ja.com

C ++では「int&foo()」とはどういう意味ですか?

左辺値と右辺値について この説明 を読んでいると、次のコード行が突き出ました:

int& foo();
foo() = 42; // OK, foo() is an lvalue

私はg ++で試しましたが、コンパイラは「foo()への未定義の参照」と言います。私が追加した場合

int foo()
{
  return 2;
}

int main()
{
  int& foo();
  foo() = 42;
}

コンパイルは問題ありませんが、実行すると セグメンテーションエラー が発生します。ラインだけ

int& foo();

コンパイルも実行も問題なく実行できます。

このコードはどういう意味ですか?関数呼び出しに値を割り当てるにはどうすればよいですか?また、なぜ右辺値ではないのですか?

111
Sossisos

説明は、有効なfooへの左辺値参照を返すintの合理的な実装があると想定しています。

そのような実装は次のとおりです。

int a = 2; //global variable, lives until program termination

int& foo() {
    return a;
} 

これで、fooは左辺値参照を返すため、次のように戻り値に何かを割り当てることができます。

foo() = 42;

これにより、グローバルaが値42で更新されます。これは、変数に直接アクセスするか、fooを再度呼び出すことで確認できます。

int main() {
    foo() = 42;
    std::cout << a;     //prints 42
    std::cout << foo(); //also prints 42
}
164
TartanLlama

他のすべての答えは、関数内で静的を宣言します。それはあなたを混乱させるかもしれないと思うので、これを見てみましょう:

int& highest(int  & i, int  & j)
{
    if (i > j)
    {
        return i;
    }
    return j;
}

int main()
{
    int a{ 3};
    int b{ 4 };
    highest(a, b) = 11;
    return 0;
}

highest()は参照を返すため、値を割り当てることができます。これが実行されると、bは11に変更されます。aがたとえば8になるように初期化を変更した場合、aは11に変更されます。他の例とは異なり、実際に目的を果たす可能性があります。

70
Kate Gregory
int& foo();

intへの参照を返すfooという名前の関数を宣言します。その例でできないのは、コンパイルできる関数の定義を提供することです。使用する場合

int & foo()
{
    static int bar = 0;
    return bar;
}

これで、barへの参照を返す関数ができました。 barはstaticであるため、関数の呼び出し後も有効なので、参照を安全に返すことができます。今なら

foo() = 42;

何が起こるかというと、参照に割り当てられ、参照はbarの単なるエイリアスであるため、42をbarに割り当てます。次のように関数を再度呼び出すと

std::cout << foo();

barを上記の値に設定したため、42が出力されます。

31
NathanOliver

int &foo();は、戻り型int&foo()という関数を宣言します。本体を提供せずにこの関数を呼び出すと、未定義の参照エラーが発生する可能性があります。

2回目の試行では、関数int foo()を提供しました。これは、int& foo();で宣言された関数とは異なる戻り型を持ちます。そのため、一致しない同じfooの2つの宣言があります。これは、1つの定義ルールに違反して未定義の動作を引き起こします(診断は不要です)。

機能するものについては、ローカル関数宣言を取り出します。あなたが見たように、それらは静かな未定義の振る舞いをもたらすことがあります。代わりに、関数の外部でのみ関数宣言を使用してください。プログラムは次のようになります。

int &foo()
{
    static int i = 2;
    return i;
}  

int main()
{
    ++foo();  
    std::cout << foo() << '\n';
}
15
M.M

int& foo();は、intへの参照を返す関数です。指定した関数は、参照なしでintを返します。

やってもいい

int& foo()
{
    static int i = 42;
    return i;
}

int main()
{
    int& foo();
    foo() = 42;
}
10
Jarod42

int & foo();は、foo()が変数への参照を返すことを意味します。

次のコードを検討してください。

#include <iostream>
int k = 0;

int &foo()
{
    return k;
}

int main(int argc,char **argv)
{
    k = 4;
    foo() = 5;
    std::cout << "k=" << k << "\n";
    return 0;
}

このコードは次を印刷します:

$ ./a.out k = 5

foo()はグローバル変数kへの参照を返すためです。

修正したコードでは、戻り値を参照にキャストしていますが、これは無効です。

7
vy32

そのコンテキストでは、&は参照を意味するため、fooはintではなくintへの参照を返します。

ポインタを使用したことがあるかどうかはわかりませんが、同様の考えです。実際に関数から値を返すのではなく、メモリ内の場所を見つけるために必要な情報を渡しますintです。

つまり、関数呼び出しに値を割り当てるのではなく、関数を使用して参照を取得し、参照される値に新しい値を割り当てています。すべてが一度に起こると考えるのは簡単ですが、実際にはコンピューターはすべてを正確な順序で実行します。

あなたが疑問に思っている場合-segfaultを取得している理由は、数値リテラル '2'を返しているためです-したがって、const intを定義してから変更しようとした場合に取得する正確なエラーです値。

ポインタと動的メモリについてまだ学習していない場合は、一度にすべてを学習しない限り理解が難しいと思われる概念がいくつかあるため、まずその方法をお勧めします。

5
Dar Brett

リンクされたページのサンプルコードは、単なるダミー関数宣言です。コンパイルはしませんが、関数を定義しておけば、一般的に機能します。この例は、「このシグネチャを持つ関数があれば、そのように使用できます」という意味でした。

この例では、fooは明らかに署名に基づいて左辺値を返しますが、左辺値に変換される右辺値を返します。これは明らかに失敗すると判断されます。あなたができる:

int& foo()
{
    static int x;
    return x;
}

次のように言うと、xの値を変更することで成功します。

foo() = 10;
4
IceFire

あなたが持っている関数foo()は、整数への参照を返す関数です。

したがって、最初にfooが5を返し、後でメイン関数でfoo() = 10;と言い、その後fooを出力すると、5ではなく10が出力されます。

私はそれが理にかなっていることを願っています:)

プログラミングも初めてです。このような質問にあなたが思うようになるのは興味深いことです! :)

3
psj01