私は数年間CおよびC++でプログラミングしており、今は大学のコースを受講しているところです。私たちの本には、例として次のような関数が含まれています。
int foo(){
int x=0;
int y=20;
return x,y; //y is always returned
}
私はそのような構文を見たことがありません。実際、,
演算子がパラメーターリストの外で使用されるのを見たことはありません。ただし、y
が常に返される場合、ポイントは何ですか?このようにreturnステートメントを作成する必要がある場合はありますか?
(また、私の本は特にC++ですが、両方に適用されるため、Cにもタグを付けました)
コンマ演算子は、主にfor
ステートメントで次のように使用されます。
for( int i=0, j=10; i<10; i++, j++ )
{
a[i] = b[j];
}
最初のコンマはコンマ演算子ではなく、宣言構文の一部です。 2番目のisコンマ演算子。
C FAQ によると:
正確に言うと、一般式におけるコンマ演算子の意味
e1、e2
は、「部分式e1を評価してからe2を評価します。式の値はe2の値です。」したがって、e1は代入または増分++または減分-または関数呼び出しまたはその他の種類の副作用を含む方がよいでしょう。
だから私はあなたに同意します、 意味はありません これが有効な構文であることを示すため以外は、.
CまたはC++で両方の値を返したい場合は、struct
およびx
メンバーを含むy
を作成し、代わりに構造体を返すことができます。
struct point {int x; int y;};
次に、タイプとヘルパー関数を定義して、struct
内の両方の値を簡単に返すことができます。
typedef struct point Point;
Point point(int xx, int yy){
Point p;
p.x = xx;
p.y = yy;
return p;
}
そして、ヘルパー関数を使用するように元のコードを変更します。
Point foo(){
int x=0;
int y=20;
return point(x,y); // x and y are both returned
}
そして最後に、あなたはそれを試すことができます:
Point p = foo();
printf("%d, %d\n", p.x, p.y);
この例は、CとC++の両方でコンパイルされます。 Markが以下に示すように、C++では、よりエレガントなソリューションを提供するpoint
構造のコンストラクターを定義できます。
ちなみに、複数の値を直接返す機能は、Pythonをサポートする言語など)ですばらしいです。
def foo():
x = 0
y = 20
return x,y # Returns a Tuple containing both x and y
>>> foo()
(0, 20)
パラメータリストのコンマは、パラメータを区切るためだけにあり、カンマ演算子とは異なります。例のように、コンマ演算子はxとyの両方を評価してから、xを破棄します。
この場合、2つの値を返そうとしたが、それを行う方法がわからなかったのは間違いだと思います。
これは実際には元の質問にはまったく答えませんが、一部の人にとっては興味深いかもしれませんが、C++で両方を返すようにしたい場合は、次のように書く必要があります(そしてc ++ 0xコンパイラが必要になります) )
Tuple<int, int> foo()
{
int x = 0;
int y = 20;
return make_Tuple(x, y);
}
このようにアクセスする-
Tuple<int, int> data = foo();
int a = get<0>(data);
int b = get<1>(data);
struct Point {
int x, y;
Point(int x_) : x(x_), y(0) {}
Point(const Point& p) : x(p.x), y(p.y) {}
Point operator, (int y_) const { Point p=*this; p.y = y_; return p; }
};
Point get_the_point () {
int x = 0;
int y = 20;
return (Point)x, y;
}
:p
ここでコメントする誰もがそれは無意味であると思うのと同じように、私は反対しません。例を見るだけで、私はそれほど良くはないと推測します:
作成者はxが関数内で使用されていないことについてコンパイラ警告を受け取っていましたが、これは警告を回避する簡単な方法でした。
この構文は、if
-ステートメントの追加のスコープブラケットを保存するために使用できます。例えば。通常、次のように記述します。
if (someThing == true)
{
a = 1;
b = 2;
return true;
}
これは次のように置き換えることができます:
if (someThing == true)
return a = 1, b = 2, true;
このコーディングスタイルの使用は、きれいなコードを書くよりも、ポーズをとるという衝動によって動機付けられていると思います。
これはコンマ演算子(、)です。
式xとyの両方が評価されます。式全体の結果はy、つまり後者の値です。
ここで使用されている理由を言うのは難しいです。デモンストレーションの目的のためでしょう。明らかに、関数は次のようにリファクタリングできます。
int foo()
{
return 20;
}
それはひどいコードの例のように見えます。これはC/C++では有効な構文かもしれませんが、あなたがそうしたいと思う理由は思いつきません。
Xとyの両方を返したい場合、C++でそれを行うより良い方法は、xおよびyプロパティを使用して「ポイント」クラスまたは構造体を定義し、それを返すことです。別のオプションは、参照によってxとyを渡し、メソッドで値を適切に設定することです。
メソッドが単にyを返す場合、「yを返す」だけです。 returnステートメントの前にxを「評価」する必要がある場合は、別の行で行う必要があります。
そのreturnステートメントには意味がありません。
x
がvolatile
と宣言された場合、アクセスは強制されます(少なくともC++ではvolatile
変数への参照は外部から観察可能な動作と見なされるため)が、 。
x
の代わりに、副作用を伴うある種の計算があった場合、その計算を行ってからy
を返します。ただし、非volatile
x
には副作用がありません。実装では、副作用や外部から観察可能な動作がないコードを実行する必要はありません。コンマ演算子は、コンマの左側にあるものをすべて実行し、結果を無視して、右側の値を実行および保持します(ただし、この場合、演算子の左側を自由に無視できます)。
したがって、return x, y;
ステートメントはreturn y;
とまったく同じです。 x
を実行するだけで完全に無意味なものでなかった場合は、まったく同じものであるx; return y;
と書くのが文体的に良いでしょう。その方法ほど混乱することはないでしょう。
Forループの外では、このコマンドオペレーターの他の主要なユーザー(関数呼び出しバージョンに相当)は、何かを行った後に値を返すマクロにあります。これらは現在これを行う他の方法ですが、comman演算子は以前は最もクリーンな方法であったと思います。
#define next(A, x, y, M) ((x) = (++(y))%(M) , A[(x)])
このマクロは、xを繰り返すため、おそらく他の理由で、マクロの悪い例です。このようにコンマ演算子を使用することはまれです。あなたの本の例は、おそらく、その例で使用可能な行数内にコード例を適合させる試みでした。
これはコンマ演算子です。そのような構文は、未使用の変数x
に関するコンパイラからの警告を無効にするために使用できます。
一方では、それは作家側の正直な間違いかもしれません。
一方、ライターは、コンパイラの警告ではなく、構文的に正しい正しいコードを説明している可能性があります。
いずれにせよ、複数の結果を返す唯一の方法は、クラスを定義してそのインスタンス、またはおそらく配列やコレクションを使用することです。
このようにreturnステートメントを作成する必要がある場合はありますか?
IMO、私は本の例のような関数で複数のリターンを使用することはありません。構造化設計に違反しています。それにもかかわらず、多くのプログラマーがいます!他の誰かのコードをデバッグする各returnステートメントでグローバル変数に値を割り当てて、どのreturnが実行されたかを確認できるようにしました。
この構文は、操作の途中で戻るときにハウスキーピングを行うためにCで使用されているのを見てきました。間違いなくメンテナンス不可能なコード:
int foo(int y){
char *x;
x = (char*)malloc(y+1);
/** operations */
if (y>100) return free(x),y;
/** operations */
if (y>1000) return free(x),y;
}
ポイントは、xの副作用(つまり、カンマ演算子の左側)です。たとえば、詳細については、Justin Ethierが回答します。
例は、C++ 11からC++ 14までのconstexpr関数の場合です。このような関数には任意のステートメントを含めることはできませんが、 1つのreturnステートメントのみを使用できます
CppCon 2016(-===-)での Patrice Roys“ The Exception Situation”のコードサンプルを次に示します :
constexpr int integral_div(int num, int denom) {
return assert(denom != 0), num / denom;
}
この本は、C++より前に他の言語を学んだ人々の潜在的な混乱を排除しようとしています。多くの言語では、同様の構文を使用して複数の値を返すことができます。 C++では警告なしでコンパイルされます(_-Wall
_または_-Wunused-value
_を指定しない限り)が、他の言語に慣れている場合は期待どおりに機能しません。最後の値を返すだけです。
ただし、C++のreturnステートメントでこのような構文を使用することは、別の言語のように誤って使用することを除いて、読みやすい状況ではないため、作者は彼が防いだよりも混乱を引き起こしたようです。彼は、ほとんどの人が試そうとは思わない使い方について警告しています。ただし、複数の代入ステートメントint x, y = foo()
も正常にコンパイルされるため、デバッグするのが非常に難しくなります。
結論:常に_-Wall
_を使用し、警告を修正します。 C++構文を使用すると、意味のない多くのことを記述できます。
return
キーワードと共に使用すると、コンマ演算子はlastの値を返します。これは最初は混乱しますですが、物をより簡潔にすることができます。
たとえば、次のプログラムはステータスコード2で終了します。
#include <iostream>
using namespace std;
void a() {
cout << "a" << endl;
}
int one() {
cout << "one" << endl;
return 1;
}
int zero() {
cout << "zero" << endl;
return 0;
}
int main() {
return one(), a(), zero(), 2;
}
以下を使用してコンパイルおよび実行すると、以下の出力が表示されます。
michael$ g++ main.cpp -o main.out && ./main.out ; echo $?
one
a
zero
2