Foo(MyStruct x):
Foo(
(x.e==A)?x:MyStruct{0,B},
(x.e==A)?MyStruct{0,A}:x
)
is a direct way to do it. Note that the same ctor is delegated to, but the arguments change. This is consistent with your example, but maybe not your real problem.
Now, suppose you have a more complex problem. You actually want a different constructor to be called based off the run time value?
If we want a different ctor to be called based on a run time value, we may have to rely on (hopefully elided) copy or move ctors.
The easy way is just
Foo(MyStruct x):
Foo( (x.e==A)?
Foo{x, {0,B}}:
Foo{{0,A}, x}
)
{}
where we invoke the Foo
copy/move ctor with a different Foo
depending on x.e
. This has the minor problem of blocking elision.
At this point you should stop. Because the next step is pretty nuts.
Here is an overly fancy way to avoid constructing the candidate Foo
s, and I think even permits elision (no clue if a compiler would actually do it):
template<class T>
struct delayed_construct {
void const* data;
T(*func)(void const*);
template<class F>
delayed_construct( F const& f ):
data(&f),
func([](void const* ptr)->T{
F const& f = *static_cast<F const*>(ptr);
return f();
})
{}
T operator()() const {
return func(data);
}
};
struct Foo {
explicit Foo( delayed_construct<Foo> d ):Foo(d()) {}
Foo(MyStruct a, MyStruct b) {}
Foo(MyStruct x):
Foo( (x.e==A)?
delayed_construct<Foo>{[&]()->Foo{
return {x, {0,B}};
}}:
delayed_construct<Foo>{[&]()->Foo{
return {{0,A}, x};
}}
)
{}
};
which does a pile of really complex stuff to allow you to pick between calling two different ctors. Even the arguments of the ctors are not evaluated if you don't pick that ctor to call.
delayed_construct<Foo>
is basically a std::function<F()>
that presumes its lifetime will be a temporary, and by doing so may be subject to slightly easier optimization by the compiler.
I believe that the standard allows the Foo
constructed in the lambdas created in Foo(MyStruct x)
to directly construct the Foo
we are calling it from. I may be wrong, and it is quite possible that even if I'm right, a compiler might not do it.