Date: Sat, 09 Aug 2025 22:06:26 +0300
Link: https://github.com/avikivity/cpp-std-proposals/blob/main/std-
constructor.md#proposal-for-stdconstructor-function-object
git: https://github.com/avikivity/cpp-std-proposals/blob/main/std-
constructor.md
Previous thread: https://lists.isocpp.org/std-
proposals/2025/07/14463.php
Changes:
- renamed to std::constructor
- made a class template instead of a variable template
- preserve noexcept
At this point, I'm asking if a committee member can volunteer to push
this forward, as I understand that's the only way to make progress, and
I cannot attend myself.
# Proposal for `std::constructor` Function Object
## I. Motivation
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 proposed `std::constructor<>` 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:
```c++
std::vector<std::vector<int>> result;
result.reserve(std::distance(input));
for (auto sz : input) {
result.emplace_back(sz);
}
```
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
```c++
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.
We propose `std::constructor<T>`, similar to std::mem_fn() but instead
of converting
a member function to a callable object, it converts a constructor
overload set to
a callable object. With std::constructor, the example above can be
written as
```c++
auto result = input
| std::views::transform(std::constructor<std::vector<int>>())
| std::ranges::to<std::vector>();
```
## III. Proposed Solution: `std::constructor`
### A. Function Signature
`std::constructor<T>()` evaluates to a function object that perfectly
forwards its arguments to T's constructors.
```c++
namespace std {
template <typename T>
struct constructor {
template <typename... Args>
static constexpr T operator()(Args&&... args)
noexcept(std::is_nothrow_constructible_v<T, Args...>) {
return T(std::forward<Args>(args)...);
};
};
}
```
### B. Semantics
- Constructs an object of type `T` using perfect forwarding
- Supports any public constructor of `T`
- Returns the constructed object by value
- Works with both trivial and complex types
- `constexpr`-compatible
- `noexcept` preserving
- if T is a reference type and std::constructor<T> attempts to bind its
return value to a temporary, the program is ill formed
## IV. Example Usage
```c++
// Basic usage (not expected in common programs)
auto str = std::constructor<std::string>()("Hello");
// Complex type construction
struct Complex {
int x, y;
Complex(int a, int b) : x(a), y(b) {}
};
auto comp = std::constructor<Complex>()(10, 20);
// Composability with std::bind_front
auto make_imag = std::bind_front(std::constructor<Complex>(), 0);
auto sqrt_minus_one = make_imag(1);
// Updated example from above
auto input = std::views::iota(0, 10);
auto result = input
| std::views::transform(std::constructor<std::vector<int>>())
| std::ranges::to<std::vector>();
// Bind an allocator to a container constructor
auto make_vector_with_alloc =
std::bind_back(std::constructor<std::vector<int>>(), std::ref(alloc));
```
## V. Design Considerations
### Advantages
- Type-safe
- No memory allocation overhead
- Works with any constructible type
- Composable with the rest of the functional library
### Potential Concerns
- Might be seen as redundant with
[P3312](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3312r1.pdf
)
### Naming
`std::constructor<T>()` is seen as consistent with std::plus<T>().
Other alternatives:
- `std::make_obj_using_allocator()` is similar. Perhaps
`std::make_obj<T>()` or `std::make_object<T>()` would work.
- `std::make_from_tuple()` is also similar. So perhaps
`std::make<T>(...)`?!
## VI. Implementation
Reference implementation:
```cpp
template <typename T>
struct constructor {
template <typename... Args>
static constexpr T operator()(Args&&... args)
noexcept(std::is_nothrow_constructible_v<T, Args...>) {
return T(std::forward<Args>(args)...);
};
};
```
## VII. Wording
TBD
## VIII. Complexity
- Time Complexity: O(1) construction time
- Space Complexity: No additional space overhead
## IX. Proposed Standardization
Recommend inclusion in the `<functional>` header in a future C++
standard revision.
## X. Acknowledgments
Thanks to Arthur O'Dwyer for correcting an ealier version on the
mailing list, and
to Claude with assistance on this draft.
constructor.md#proposal-for-stdconstructor-function-object
git: https://github.com/avikivity/cpp-std-proposals/blob/main/std-
constructor.md
Previous thread: https://lists.isocpp.org/std-
proposals/2025/07/14463.php
Changes:
- renamed to std::constructor
- made a class template instead of a variable template
- preserve noexcept
At this point, I'm asking if a committee member can volunteer to push
this forward, as I understand that's the only way to make progress, and
I cannot attend myself.
# Proposal for `std::constructor` Function Object
## I. Motivation
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 proposed `std::constructor<>` 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:
```c++
std::vector<std::vector<int>> result;
result.reserve(std::distance(input));
for (auto sz : input) {
result.emplace_back(sz);
}
```
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
```c++
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.
We propose `std::constructor<T>`, similar to std::mem_fn() but instead
of converting
a member function to a callable object, it converts a constructor
overload set to
a callable object. With std::constructor, the example above can be
written as
```c++
auto result = input
| std::views::transform(std::constructor<std::vector<int>>())
| std::ranges::to<std::vector>();
```
## III. Proposed Solution: `std::constructor`
### A. Function Signature
`std::constructor<T>()` evaluates to a function object that perfectly
forwards its arguments to T's constructors.
```c++
namespace std {
template <typename T>
struct constructor {
template <typename... Args>
static constexpr T operator()(Args&&... args)
noexcept(std::is_nothrow_constructible_v<T, Args...>) {
return T(std::forward<Args>(args)...);
};
};
}
```
### B. Semantics
- Constructs an object of type `T` using perfect forwarding
- Supports any public constructor of `T`
- Returns the constructed object by value
- Works with both trivial and complex types
- `constexpr`-compatible
- `noexcept` preserving
- if T is a reference type and std::constructor<T> attempts to bind its
return value to a temporary, the program is ill formed
## IV. Example Usage
```c++
// Basic usage (not expected in common programs)
auto str = std::constructor<std::string>()("Hello");
// Complex type construction
struct Complex {
int x, y;
Complex(int a, int b) : x(a), y(b) {}
};
auto comp = std::constructor<Complex>()(10, 20);
// Composability with std::bind_front
auto make_imag = std::bind_front(std::constructor<Complex>(), 0);
auto sqrt_minus_one = make_imag(1);
// Updated example from above
auto input = std::views::iota(0, 10);
auto result = input
| std::views::transform(std::constructor<std::vector<int>>())
| std::ranges::to<std::vector>();
// Bind an allocator to a container constructor
auto make_vector_with_alloc =
std::bind_back(std::constructor<std::vector<int>>(), std::ref(alloc));
```
## V. Design Considerations
### Advantages
- Type-safe
- No memory allocation overhead
- Works with any constructible type
- Composable with the rest of the functional library
### Potential Concerns
- Might be seen as redundant with
[P3312](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3312r1.pdf
)
### Naming
`std::constructor<T>()` is seen as consistent with std::plus<T>().
Other alternatives:
- `std::make_obj_using_allocator()` is similar. Perhaps
`std::make_obj<T>()` or `std::make_object<T>()` would work.
- `std::make_from_tuple()` is also similar. So perhaps
`std::make<T>(...)`?!
## VI. Implementation
Reference implementation:
```cpp
template <typename T>
struct constructor {
template <typename... Args>
static constexpr T operator()(Args&&... args)
noexcept(std::is_nothrow_constructible_v<T, Args...>) {
return T(std::forward<Args>(args)...);
};
};
```
## VII. Wording
TBD
## VIII. Complexity
- Time Complexity: O(1) construction time
- Space Complexity: No additional space overhead
## IX. Proposed Standardization
Recommend inclusion in the `<functional>` header in a future C++
standard revision.
## X. Acknowledgments
Thanks to Arthur O'Dwyer for correcting an ealier version on the
mailing list, and
to Claude with assistance on this draft.
Received on 2025-08-09 19:06:34