I would like to trigger a specific constructor for a member variable based on flags I pass to the containing class's constructor.
It's easiest if I start with a trivial example:
#include <boost/optional.hpp>
#include <boost/none.hpp>
#include <boost/utility/typed_in_place_factory.hpp>
struct state
{
bool flag1;
bool flag2;
int value;
};
class A
{
public:
A() : _a() {}
A(boost::none_t none) : _a() {}
A(state& st) : _a(st.value) {}
A(const A& copy) : _a(copy._a) {}
private:
boost::optional<int> _a;
};
class B
{
public:
B() : _b() {}
B(boost::none_t none) : _b() {}
B(state& st) : _b(st.value) {}
B(const B& copy) : _b(copy._b) {}
private:
boost::optional<int> _b;
};
class C
{
public:
C() : _a(boost::none_t()), _b(boost::none_t()) {}
C(state& st) :
_a(st.flag1 ? st : boost::none_t()),
_b(st.flag2 ? st : boost::none_t())
{}
private:
boost::optional<A> _a;
boost::optional<B> _b;
};
int main(void)
{
state f = { true, false, 10 };
C c(f);
return 0;
}
So the idea is to trigger the constructor for A
with state
, but B
with boost::none_t
.
The above code does not compile because the ternary operator is expecting the same type for both possibilities, and state
and boost::none_t
are not the same type.
Can anyone think of an elegant way around this?
I know of two solutions:
Copy construct, i.e.
_a(st.flag1 ? A(st) : A(boost::none_t())),
_b(st.flag2 ? B(st) : B(boost::none_t()))
Use pointers instead of boost::optional<>
, then
_a(st.flag1 ? new A(st) : new A(boost::none_t())),
_b(st.flag2 ? new B(st) : new B(boost::none_t()))
#2 is not so appealing, as I'm trying to avoid dynamic memory allocation (the real example has tens of members and deeply nested structures with more members).
#1 is also not appealing as I would need to construct and then copy.
Is there a better alternative?
EDIT: state
is modified by the members on construction, so I don't want to construct something with state
if the flag is not set.
You have to learn to trust your compiler's optimiser to inline this kind of thing adequately, or you'll restrict yourself from using 99% of the Standard libraries and advanced C++ facilities.
Start by looking at the boost optional API:
...
optional(bool condition, T const&);
...
Which suggests adding a matching constructor...
A(bool condition, T const& v) : _a(condition, v) { }
...and using it in your initialisation...
_a(st.flag1, st.value)
It appears that using boost::optional<>
is complicating things, using it with the copy constructed approach seems to cause both the state
based and copy based constructors of A
& B
to be called - even with full optimization.
However, if I define the members of C
as simply A _a
and B _b
, the copy constructor is actually optimised away, so doing
_a(st.flag1? A(st) : A()), _b(st.flag2? B(st) : B())
Is actually apparently the most optimal way of getting this to work, I just have to workaround the other functionality I was using from boost::optional<> (i.e. initialized vs. uninitialized).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With