This is kind of a follow up to this question, where I asked how I could tersely turn a template and/or overloaded function into a function object.
The accepted answer was you can't do without macro, which is correct. Then I found that such a macro is offered by Boost, in the form of the BOOST_HOF_LIFT
and BOOST_HOF_LIFT_CLASS
macros.
It turns out, however, that there are other "named things" you can't pass around. I don't know all of them, but one of them is constructors. And Boost.Hof offers a way to lift them to, via boost::hof::construct
.
The point is that not even boost::hof::construct
can deal with a class without a user-declared constructor. For intance, given
struct Foo {
int foo;
};
the call boost::hof::construct<Foo>()(3)
simply doesn't work. (Adding the constructor Foo(int) {}
in Foo
makes it work; that's what boost::hof::construct
is for, after all.)
Surely, in simple cases like the one above I could just write
auto makeFoo = [](int x){ return Foo{x}; };
but if I want to support any type, I have to take care of perfect forwarding and variadic arguments.
Is there a library offering this feature already? It doesn't look like Boost.Hof does...
If you want a function object that constructs an object of some type T
given some parameters, even if T
is an aggregate, that's not difficult to write in C++17:
template<typename T>
struct lifted_construct
{
template<typename ...Args>
T operator() (Args&& ...args)
{
if constexpr(std::is_aggregate_v<T>)
{
return T{std::forward<Args>(args)...};
}
else
{
return T(std::forward<Args>(args)...);
}
}
};
Of course, in C++20, you can use ()
syntax even for aggregates.