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.