2017-05-05 18 views
0

デフォルトイニシャライザでプレーンな古いメンバ関数を使用して "ワンタイム"ラムダを使用することに違いはありますか?対メンバ関数を使用してデフォルトイニシャライザでラムダを使用する

struct A 
{ 
    int i; 
    int j = [&] 
    // something non-trivial, 
    // that requires multiple 
    // statements and depends 
    // on upper data members 
    { 
     int f = 0; 
     for (int k = 0; k < i; ++k) { 
      f += k; 
     } 
     return f; 
    }(); 
    A(int k) : i(k) { ; } 
}; 

struct A 
{ 
    int i; 
    int J() const 
    { 
     int f = 0; 
     for (int k = 0; k < i; ++k) { 
      f += k; 
     } 
     return f; 
    } 
    int j = J(); 
    A(int k) : i(k) { ; } 
}; 

私は見るだけでは、第二のアプローチの欠点である:クラスAの名前空間に導入され、ここで、余分なシンボルJ。別の区別がありますか?

+0

個人的には、関数を使用して、メンバー初期化リストの計算に必要な変数を渡します。それ以外の場合は、クラス内の変数の順序を変更することは決してありません。 – NathanOliver

+0

ラムダの初期化を使ったあなたの例はコンパイルされません。 – vordhosbn

+0

@vordhosbn:親がいなくなった。 – Jarod42

答えて

1

パフォーマンスに関しては、gcc 7.1 -O3コンパイルコードに違いはありません。どちらの実装も同じアセンブリを生成します。

テストコード:

int callerFunc(int init) 
{ 
    A st(init); 
    return st.j; 
} 

がにコンパイルさ:

callerFunc(int): 
     test edi, edi 
     jle  .L7 
     lea  eax, [rdi-1] 
     cmp  eax, 7 
     jbe  .L8 
     pxor xmm0, xmm0 
     mov  edx, edi 
     xor  eax, eax 
     movdqa xmm1, XMMWORD PTR .LC0[rip] 
     shr  edx, 2 
     movdqa xmm2, XMMWORD PTR .LC1[rip] 
.L5: 
     add  eax, 1 
     paddd xmm0, xmm1 
     paddd xmm1, xmm2 
     cmp  eax, edx 
     jb  .L5 
     movdqa xmm1, xmm0 
     mov  edx, edi 
     and  edx, -4 
     psrldq xmm1, 8 
     paddd xmm0, xmm1 
     movdqa xmm1, xmm0 
     cmp  edi, edx 
     psrldq xmm1, 4 
     paddd xmm0, xmm1 
     movd eax, xmm0 
     je  .L10 
.L3: 
     lea  ecx, [rdx+1] 
     add  eax, edx 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+2] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+3] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+4] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+5] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+6] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     add  edx, 7 
     lea  ecx, [rax+rdx] 
     cmp  edi, edx 
     cmovg eax, ecx 
     ret 
.L7: 
     xor  eax, eax 
.L1: 
     rep ret 
.L10: 
     rep ret 
.L8: 
     xor  eax, eax 
     xor  edx, edx 
     jmp  .L3 
.LC0: 
     .long 0 
     .long 1 
     .long 2 
     .long 3 
.LC1: 
     .long 4 
     .long 4 
     .long 4 
     .long 4 
0

違いのカップルが頭に浮かぶ:

  1. ラムダがオーバーロードすることはできません。したがって、継承されたクラスはすべて同じ関数を使用します。
  2. ラムダを使うと、デフォルトでローカル変数を取得することができます。これにより、名前の変更/並べ替えが行われるとバグが発生する可能性があります。これらを明示的に渡すと、これを軽減できます。 re-orderingはメソッドとlambdaの両方にとって危険ですが、デフォルトのラムダキャプチャは、変更する変数が暗黙的にラムダに渡されるため、より揮発性です。
+2

意味のある方法で 'J'を過負荷にする方法はありません。なぜなら、それは構築時に呼び出され、あらゆる時点で仮想仮想過負荷が接続されないからです。 – Yakk

+1

そして、方法は変数の順序付けについて同じ落とし穴があります。 – Jarod42

+0

@ Jarod42 Trueですが、並べ替えられた変数が必ずしもメソッドに渡されるわけではないため、デフォルトキャプチャよりもリスクは低くなります。 – nikaza

関連する問題