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.
It appears that using
boost::optional<>is complicating things, using it with the copy constructed approach seems to cause both thestatebased and copy based constructors ofA&Bto be called – even with full optimization.However, if I define the members of
Cas simplyA _aandB _b, the copy constructor is actually optimised away, so doingIs 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).