引数を参照渡しで渡せばよい
関数では戻り値を使って、呼び出し元に何らかの計算結果を返すことができます。
しかし、戻り値で返すことのできる値は1つだけです。
では、関数で2つ以上の値を返したい場合はどうすれば良いでしょうか?
主な方法は2つ。
1つ目は返したい値の数だけ関数を作成する方法。コードの可読性だけで決めるならこれが一番です。分かりやすい関数名を各々に付けられますしね。原則はこれです。
ただ、複数の関数に分けると、同じようなアルゴリズムを持つ関数が量産されやすく、保守性が下がります。また、戻り値が2つ返せるなら1回の計算で済むような場合でも、関数を分けることで、同じ計算を2回することになり、結果として実行速度が低下します。
こういった問題があるので、1つの関数で完結した方が望ましいこともあります。
そこで、2つ目の方法です。それは、返したい値を引数の参照渡しで関数に渡す方法です。
実例を用いた解説
加重平均約定価格を計算する関数で加重平均約定価格合計ロット数の2つの値を返したい場合を例にとって説明します。
加重平均約定価格を計算する関数では、戻り値として加重平均約定価格を返します。そこに、合計ロット数もセットで返したくなったと仮定します。
2つの値を返したくなったので、戻り値をやめて引数の参照渡しを利用します(別に戻り値をやめなくてもいいのですが、分かりやすくするために、複数の値を返す時は戻り値のない関数に変えることが多いです)。
加重平均約定価格と合計ロット数を返したいので、この2つの変数を呼び出し元側で用意した上で、以下のように引数の前にアンパサンド(&記号)を加えます。この&記号が参照渡しを表しています。
//+------------------------------------------------------------------+ //|【関数】加重平均約定価格を計算する | //| | //|【引数】 IN OUT 引数名 説明 | //| --------------------------------------------------------- | //| ○ aAvgEntryPrice 加重平均約定価格 | //| ○ aTotalLot 合計ロット数 | //| ○ aMagic マジックナンバー | //| | //|【戻値】なし | //| | //|【備考】なし | //+------------------------------------------------------------------+ void averageEntryPrice(double &aAvgEntryPrice, double &aTotalLot, int aMagic) { double sumPrice_x_Lot = 0.0; double sumLot = 0.0; for(int i = 0; i < OrdersTotal(); i++){ if(OrderSelect(i, SELECT_BY_POS) == false){ break; } if(OrderSymbol() != Symbol() || OrderMagicNumber() != aMagic){ continue; } sumPrice_x_Lot += NormalizeDouble(OrderOpenPrice(), Digits) * OrderLots(); sumLot += OrderLots(); } aTotalLot = sumLot; // ゼロ割り防止 if(sumLot == 0.0){ aAvgEntryPrice =0.0; }else{ aAvgEntryPrice = NormalizeDouble(sumPrice_x_Lot / sumLot, Digits); } }
&記号を付けた引数aAvgEntryPrice、aTotalLotは、averageEntryPrice関数内で計算され、その結果が格納された状態で呼び出し元に返されます。
逆に、&記号をつけないと呼び出し元には計算結果が反映されません(呼び出した時の変数の値のままです)。呼び出し元には計算結果が反映されない(&記号を付けない)引数の渡し方を値渡しと言います。
引数には参照渡しと値渡しの2種類が存在していて、関数内での計算結果を呼び出し元に返すか返さないかで使い分けるんだということを覚えておきましょう。
なお、返したい値の数が不確定の場合は、配列変数を利用すればよいでしょう。