一般に、C++ は名前による呼び出しを使用しません。名前による呼び出しとは、関数への引数が関数呼び出しで評価されないことを意味します。引数が関数本体に代入されたかのように動作します。
例:
void foo(int a, int b) {
int s = 0;
for(int i=0; i<n; i++) {
s += b;
}
}
通常、C++ では、式の例は次のようx = foo(3,bar(7));
に動作します。
int tmp = bar(7);
x = foo(3,tmp);
bar
は 1 回評価され、その結果が関数に渡されますfoo
。
名前による呼び出しを使用する言語は、潜在的に次のように変換foo(3,bar(7));
されます。
void foo() {
int s = 0;
for(int i=0; i<3; i++) {
s += bar(7);
}
}
最初のケースでは関数bar
は 1 回評価され、2 番目のケースでは複数回評価され3
ます。
ただし、その規則には例外があります。関数宣言が既知の場合 (テンプレートやインラインなど)、オプティマイザはそれを使用して最適化されたコードを生成できます。
例:
inline unsigned foo(unsigned a, unsigned b) {
return a / b;
}
a = foo(x,2);
コンパイラを呼び出すa = x/2;
と、それをに変換してから に変換するのに十分なほどスマートになりa = x >> 1;
ます。
これは、次の例にも当てはまります。
inline int foo(int a, int b) {
if(a == 0) return 0;
else return b;
}
これで、コンパイラは実際に関数を呼び出さないように変換x = foo(0,bar(17));
できx = 0;
ますbar
。bar
この最適化は、副作用がないことが保証されている場合にのみ行われると思います。
C++ は名前による呼び出しを使用しませんが、C++ ではイデオムを簡単に使用できます。関数に関数オブジェクト/ポインターを与えるだけです。
例:
template<typename F>
int foo(int a, F b) {
int s = 0;
for(int i=0; i<a; i++) {
s += b();
}
}
foo(3, []() { static int i=0; return i++; })
2 番目の引数が C++11 ラムダである では、コード内で b が検出されるたびに評価されます。