C++ users can convert member functions to funtion objects with std::mem_fn(), partially bind arguments to functions or function objects with std::bind, std::bind_front(), and std::bind_back(), type-erase them with std::function<>, and use them to transform ranges with std::views::transform. But none of that can be done directly to class constructors; a helper function must be used to "downgrade" the constructor into a function.
The proposedstd::construct<>is a utility function object that provides a convenient, generic mechanism to convert a constructor overload set into a function object, thereby allowing all the existing tooling for function objects to be brought to bear on it.
II. Example Problem
Imagine you have a range of size_t and you wish to return a vector of vectors, with the sizes given from the given range. Naive code can look like:
However, this is unsatisfying. The input range may be an input_range, which does not afford two passes (one for std::distance, one for the for loop). The emplace_back loop is less efficient than constructing the vector from a range.
A modern range-based solution would look like
auto result = input
| std::views::transform([] (size_t sz) {
return std::vector<int>(sz);
}
| std::ranges::to<std::vector>();
This is still unsatisfying, as the lambda is not concise.
III. Proposed Solution:std::construct
A. Function Signature
std::construct<T>evaluates to a function object that perfectly forwards its arguments to T's constructors.
Constructs an object of typeTusing perfect forwarding
Supports any constructor ofT
Returns the constructed object by value
Works with both trivial and complex types
constexpr-compatible
if T is a reference type and std::construct attempts to bind its return value to a temporary, the program is ill formed
IV. Example Usage
// Basic usageauto str = std::construct<std::string>("Hello");
// Complex type constructionstructComplex {
int x, y;
Complex(int a, int b) : x(a), y(b) {}
};
auto comp = std::construct<Complex>(10, 20);
// Composability with std::bind_frontauto make_imag = std::bind_front(std::construct<Complex>, 0);
auto sqrt_minus_one = make_imag(1);
// Updated example from aboveauto result = input
| std::views::transform(std::construct<std::vector<int>>)
| std::ranges::to<std::vector>();
V. Design Considerations
Advantages
Type-safe
No memory allocation overhead
Works with any constructible type
Composable with the rest of the functional library