特別な構造体を操作しようとしていますが、ある種のスウィズル演算子が必要です。このため、オーバーロードされた配列演算子を使用することは理にかなっています[]
が、構造体の特定の仕様により理論的な回避策が可能になるため、分岐はしたくありません。
現在、構造体は次のようになっています。
struct f32x4
{
float fLow[2];
float fHigh[2];
f32x4(float a, float b, float c, float d)
{
fLow[0] = a;
fLow[1] = b;
fHigh[0] = c;
fHigh[1] = d;
}
// template with an int here?
inline float& operator[] (int x) {
if (x < 2)
return fLow[x];
else
return fHigh[x - 2];
}
};
ブランチを回避するにはどうすればよいですか? 私の考えでは、整数パラメーターを持つテンプレートを使用して特殊化を定義することですが、それが理にかなっているかどうか、およびそのモンスターの構文がどのように見えるかは明らかではありません。
私は明示的に、いかなる状況下でも、float[4]
配列を使用して 2 つをマージすることはできません (また、ユニオン トリックはありません)。その正当な理由が必要な場合は、float[2]
実際には、プラットフォーム固有の PowerPC ペア シングルに似ているためです。通常の Windows コンパイラはペアのシングルでは動作しません。そのため、コードをfloat[2]
s に置き換えました。
GreenHills コンパイラを使用すると、次のアセンブリ出力が得られます (分岐が発生していることを示唆しています)。
.LDW31:
00000050 80040000 89 lwz r0, 0(r4)
00000054 2c000000 90 cmpwi r0, 0
00000058 41820000 91 beq .L69
92 #line32
93
94 .LDWlin1:
0000005c 2c000001 95 cmpwi r0, 1
00000060 40820000 96 bne .L74
97 #line32
98
99 .LDWlin2:
00000064 38630004 100 addi r3, r3, 4
00000068 38210018 101 addi sp, sp, 24
0000006c 4e800020 102 blr
103 .L74:
00000070 2c000002 104 cmpwi r0, 2
00000074 40820000 105 bne .L77
106 #line33
107
108 .LDWlin3:
00000078 38630008 109 addi r3, r3, 8
0000007c 38210018 110 addi sp, sp, 24
00000080 4e800020 111 blr
112 .L77:
00000084 2c000003 113 cmpwi r0, 3
00000088 40820000 114 bne .L80
115 #line34
116
117 .LDWlin4:
0000008c 3863000c 118 addi r3, r3, 12
00000090 38210018 119 addi sp, sp, 24
00000094 4e800020 120 blr
121 .L80:
00000098 38610008 122 addi r3, sp, 8
123 .L69:
124 # .ef
そのスニペットに対応する C++ コードは次のようになります。
inline const float& operator[](const unsigned& idx) const
{
if (idx == 0) return xy[0];
if (idx == 1) return xy[1];
if (idx == 2) return zw[0];
if (idx == 3) return zw[1];
return 0.f;
}