私は最近、名前付きパラメーターのイディオムが役立つ状況にかなりの数の状況に遭遇しましたが、コンパイル時に保証されることを望みます。チェーン内の参照を返す標準的な方法は、ほとんどの場合、ランタイム コンストラクター (Clang 3.3 -O3 でコンパイル) を呼び出すように見えます。
これを参照して何かを見つけることができなかったので、これを機能させようとしてconstexpr
機能的なものを手に入れました:
class Foo
{
private:
int _a;
int _b;
public:
constexpr Foo()
: _a(0), _b(0)
{}
constexpr Foo(int a, int b)
: _a(a), _b(b)
{}
constexpr Foo(const Foo & other)
: _a(other._a), _b(other._b)
{}
constexpr Foo SetA(const int a) { return Foo(a, _b); }
constexpr Foo SetB(const int b) { return Foo(_a, b); }
};
...
Foo someInstance = Foo().SetB(5).SetA(2); //works
これは少数のパラメーターでは問題ありませんが、数が多い場合はすぐに混乱します。
//Unlike Foo, Bar takes 4 parameters...
constexpr Bar SetA(const int a) { return Bar(a, _b, _c, _d); }
constexpr Bar SetB(const int b) { return Bar(_a, b, _c, _d); }
constexpr Bar SetC(const int c) { return Bar(_a, _b, c, _d); }
constexpr Bar SetD(const int d) { return Bar(_a, _b, _c, d); }
より良い方法はありますか?多くの(30以上)パラメータを持つクラスでこれを行うことを検討していますが、将来拡張するとエラーが発生しやすくなるようです。
編集: C++1y タグを削除しました -- C++1y は問題を修正しているように見えますが (TemplateRex に感謝します!)、これは製品コード用であり、C++11 で立ち往生しています。それが無理なら、その通りだと思います。
EDIT2:これを探している理由を示すために、ユースケースを示します。現在、私たちのプラットフォームでは、開発者はハードウェア構成のビット ベクトルを明示的に設定する必要があります。これは問題ありませんが、非常にエラーが発生しやすくなっています。C99 拡張機能の指定された初期化子を使用しているものもありますが、これは問題ありませんが、標準ではありません。
HardwareConfiguration hardwareConfig = {
.portA = HardwareConfiguration::Default,
.portB = 0x55,
...
};
ただし、ほとんどはこれを使用しておらず、数字の塊を入力しているだけです。したがって、実際の改善として、次のようなものに移行したいと思います (より良いコードを強制するため):
HardwareConfiguration hardwareConfig = HardwareConfiguration()
.SetPortA( Port().SetPolarity(Polarity::ActiveHigh) )
.SetPortB( Port().SetPolarity(Polarity::ActiveLow) );
これははるかに冗長かもしれませんが、後で読むとはるかに明確になります。