I recently came across quite a few situations where a Named Hierarchical Parameter would be useful, but I would like it to be guaranteed at compile time. The standard method for returning links in a chain almost always calls a run-time constructor (compilation with Clang 3.3-O3).
I was not able to find anything with a reference to this, so I tried to get this to work with constexpr and got something functional:
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);
While this is good for a small number of parameters, for large numbers it quickly explodes into a mess:
//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); }
Is there a better way? I look at this with classes that have many (30+) parameters, and it looks like it will be error prone if it is expanded in the future.
EDIT: Remote C ++ 1y tag - while C ++ 1y really fixes the problem (thanks to TemplateRex!), This is for production code and we are stuck with C ++ 11. If that means it is not possible then I I suppose that's the way it is.
EDIT2: To show why I'm looking for this, here is a usage example. Currently, with our platform, developers need to explicitly set bit vectors for hardware configurations, and although this is normal, it is very error prone. Some use designated initializers from the C99 extension, which is good, but non-standard:
HardwareConfiguration hardwareConfig = { .portA = HardwareConfiguration::Default, .portB = 0x55, ... };
Most, however, do not even use this, but simply enter blob numbers. So, as an improvement, I would like to move on to something similar (since it also creates better code):
HardwareConfiguration hardwareConfig = HardwareConfiguration() .SetPortA( Port().SetPolarity(Polarity::ActiveHigh) ) .SetPortB( Port().SetPolarity(Polarity::ActiveLow) );
Which may be much more detailed, but much clearer when reading later.