Here comes the implementation as well:
```cpp
If (not this->has_value())
return nullopt;
/*define Local struct emplacer_t as before */
return optional<U>
{ in_place, emplacer_t{ fn } };
```
The `in_place_t` constructor template can be used to explicitly initialize an instance of `optional`. No extra constructor is needed.
You're original problem was to use an "invocable" as an input to a public standard constructor. I gave you the emplacer idiom as the solution to replace an "invocable" with a "convertible" in my initial answer, assuming that you'd figure the proper constructor to apply the convertible. In this post I demonstrated the proper constructor too. I hope you can connect the dots at this point.
Okay, you want to make me do the work here. Fine.
Here's a complete working example of how to use the emplacer idiom to construct an optional containing an immovable object, where that immovable object is initialized by calling a function that returns it by value:
#include <functional>
#include <optional>
struct Immovable1 {
Immovable1(int) {}
Immovable1(const Immovable1&) = delete;
static Immovable1 make() { return {1}; }
};
template <class F>
struct Emplacer {
F&& f;
operator std::invoke_result_t<F>() const {
return std::invoke((F&&)f);
}
};
template <class F>
std::optional<std::invoke_result_t<F>> makeOptional(F&& f) {
return std::optional<std::invoke_result_t<F>>{std::in_place, Emplacer{(F&&)f}};
}
auto o1 = makeOptional(Immovable1::make);
But let me show you a different value type for which this implementation doesn't work:
struct Immovable2 {
Immovable2(int) {}
Immovable2(const Immovable2&) = delete;
Immovable2(auto&&... args) {
static_assert(sizeof...(args) > 100); // always false
}
static Immovable2 make() { return {1}; }
};
auto o2 = makeOptional(Immovable2::make); // triggers the static assertion
The reason why this fails is that instead of using the emplacer's conversion function to initialize the `Immovable2` object, the `optional` constructor will instantiate and attempt to use the `Immovable2(auto&&...)` constructor (at which point the static assertion fires because there is only one argument, not more than 100). So, you see, if the type has a constructor like this, then the emplacer idiom doesn't work, because that constructor is "too good" in overload resolution.
I think that I explained this very clearly in one of my previous messages: "If the type that needs to be constructed has an unconstrained
constructor template, that constructor template will be used and the
emplacer's conversion function will not be used."
how am I supposed to end the twisted road of your hair in such a dark night??
unless the candle of your face does shed some light upon my way!!!
Now you're skipping my response without enough proper attention and focus.
I think you should take a step back and consider that you did not actually explain how to construct the `optional`. You explained the emplacer idiom, but you didn't show how to use it to implement `transform`. If I haven't understood you, it's because you haven't explained completely.
I've actually implemented the monadic operations for `optional`, so I know how to use the emplacer idiom, so I've filled in the blanks in your email, and I've explained why the approach is not perfect. If you meant something different than what I meant, then you should show a working proof-of-concept implementation of `transform`.
The emplacer object is constructed and explicitly converted by the impelementation. The point of using emplacer idiom is to replace a function call with a conversion, so the constructor/`emplace` member of result object won't need an extra move construction. The result object `optional<U>` has an explicit and fully specified type, so there will be no mistakes:
```cpp
template<typename T, typename F>
auto optioal<T>::transform(F&&)
-> optional<remove_cvref_t<invoke_result_t<F, T&>>>;
```
How do you construct an `optional<U>` where `U` is immovable and the value of the contained `U` object is obtained by calling some function, call it `f`, that returns `U` by value? Which constructor of `optional<U>` do you call in order to do this?
Do you do it like this?
return optional<U>(emplacer{...});
And I am telling you that this will not do the right thing if `U` happens to have a constructor like:
template <class V>
U(V&&);
Result type is already known, So there's only a simple construction/emplace required for the result. Depending on implementation, emplacer idiom may or may not be required. Anything `F` returns, will be stripped off its qualifiers before converting into an `optional`. Compile fails if proper copy/move constructors are unavailable. Now If your argument is based on constraining standard library, that'll be a total reboot not limited to a specific member function of a specific class.
how am I supposed to end the twisted road of your hair in such a dark night??
unless the candle of your face does shed some light upon my way!!!
Send Std-Discussion mailing list submissions to
std-discussion@lists.isocpp.org
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
or, via email, send a message with subject or body 'help' to
std-discussion-request@lists.isocpp.org
You can reach the person managing the list at
std-discussion-owner@lists.isocpp.org
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Std-Discussion digest..."
Today's Topics:
1. Re: Std-Discussion Digest, Vol 81, Issue 10 (Brian Bi)
---------- Forwarded message ----------
From: Brian Bi <bbi5291@gmail.com>
To: std-discussion@lists.isocpp.org
Cc: Farid Mehrabi <farid.mehrabi@gmail.com>
Bcc:
Date: Wed, 17 Dec 2025 15:11:46 -0500
Subject: Re: [std-discussion] Std-Discussion Digest, Vol 81, Issue 10
What you're calling `U` is what I called `T` in my example (the type that needs to be constructed).
If the type that needs to be constructed has an unconstrained constructor template, that constructor template will be used and the emplacer's conversion function will not be used. That is the problem.
I guess you're missinterpreting the usage of `transform`. The output type `U` is deduced from `invoke_result_t<F>`. It has nothing to do with original `T`. If the `F` instance doesn't mutate the original `T` instance, it won't be modified. `T` and `U` don't need to have any relation; the requirment is `invocable<F(T&)>`(`T` reference gets same qualifiers as `this`), and `U` is deduced to `auto{f(t)}`.
how am I supposed to end the twisted road of your hair in such a dark night??
unless the candle of your face does shed some light upon my way!!!
Send Std-Discussion mailing list submissions to
std-discussion@lists.isocpp.org
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
or, via email, send a message with subject or body 'help' to
std-discussion-request@lists.isocpp.org
You can reach the person managing the list at
std-discussion-owner@lists.isocpp.org
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Std-Discussion digest..."
Today's Topics:
1. Re: Std-Discussion Digest, Vol 81, Issue 8 (Brian Bi)
---------- Forwarded message ----------
From: Brian Bi <bbi5291@gmail.com>
To: std-discussion@lists.isocpp.org
Cc: Farid Mehrabi <farid.mehrabi@gmail.com>
Bcc:
Date: Wed, 17 Dec 2025 14:17:57 -0500
Subject: Re: [std-discussion] Std-Discussion Digest, Vol 81, Issue 8
There's a very unpopular idiom about this. I call it the **emplacer** idiom, which can be used in many different scenarios where the proper constructor is not available. It relies on the C++20 mandated direct initialization on returned objects:
```cpp
template<invocable<> F>
struct implacer_t{
F&& fn;
operator auto() const
{ return invoke(forward<F>(fn)); };
}; // ! emplacer
```
The `emplacer_t` class converts any references to invocable objects into conversion to returned object, and can be fed to `emplace` members of any standard class. It can also be used to call private constructors of classes while using `make_unique` or `make_shared`. Usage is as simple as:
```cpp
auto fn = []<typname ...A>(A&&...v)
{ return T{forward<A>(v)}; };
my_obj.emplace
( emplacer_t
{ bind(fn,args...) } );
```
I just think that the emplacer idiom requires standard exposition. A few convenience CPO should be added, that make the idiom publicly available to standard library users:
I am sure that the standard library implementors know this trick. The problem is that it doesn't actually let you implement the spec perfectly. Consider the case of an `optional<T>` where `T` has a constructor like this:
template <class U>
T(U&&);
In other words, there is an implicit conversion from any type to `T`. Now, if you attempt to construct a `T` using what you've called the emplacer idiom, this constructor will be called, since it will win overload resolution compared with the alternative of calling the move constructor of `T` (with the T&& binding to the T returned by the emplacer's conversion function).
So, I think the only way to actually implement the spec is to add an extra constructor like the standard library devs have done. This does appear to be an issue with the spec since it breaks user-defined specializations of `optional` like Rasheeg points out, and LWG should decide what to do about it, e.g.:
- ban user-defined specializations of `optional`?
- recommend to LEWG that they add the necessary constructor to the public interface?
- modify the spec so that it explicitly uses the emplacer idiom (thus not requiring support for cases where the emplacer idiom doesn't work)?
- `default_emplacer` a CPO that can convert to any object with public default constructor via calling the constructor.
- `emplace_args` embeds a forwarding tuple and returns an object constructed from tuple elements upon conversion.
- `emplace_result` the most generic case that wraps the `emplacer_t` class and returns an instance.
These 3 CPO can help in various situations of emplacement in user code.
Regards,
FM.
how am I supposed to end the twisted road of your hair in such a dark night??
unless the candle of your face does shed some light upon my way!!!
Send Std-Discussion mailing list submissions to
std-discussion@lists.isocpp.org
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
or, via email, send a message with subject or body 'help' to
std-discussion-request@lists.isocpp.org
You can reach the person managing the list at
std-discussion-owner@lists.isocpp.org
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Std-Discussion digest..."
Today's Topics:
1. Implementing std::optional<T>::transform (Rasheeq Azad)
---------- Forwarded message ----------
From: Rasheeq Azad <rasheeqhere@gmail.com>
To: Std-Discussion@lists.isocpp.org
Cc:
Bcc:
Date: Sun, 14 Dec 2025 16:00:00 -0500
Subject: [std-discussion] Implementing std::optional<T>::transform
In the current draft, [optional.monadic] specifies that
std::optional<T>::transform(F &&f) & shall do the following:
> Let U be remove_cv_t<invoke_result_t<F, decltype(*val)>>.
> Mandates: ...
> [Note 1: There is no requirement that U is movable ([dcl.init.general]).
> Returns: If *this contains a value, an optional<U> object whose contained value is direct-non-list-initialized with invoke(std::forward<F>(f), *val); otherwise, optional<U>().
I'm wondering how this is supposed to be implemented. None of the
standard constructors of std::optional<U> directly support
initializing the contained object with an invocable. Both GCC
libstdc++ [1a] [1b] [1c] and LLVM libc++ [2a] [2b] [2c] get around
this by adding an internal-use-only (using a tag type that has a
reserved name) constructor to std::optional<T> that takes the
invocable and calls it to initialize the contained object. But this
means that std::optional<T> relies on the *different specialization*
std::optional<U> supporting this nonstandard constructor.
As a consequence, neither library can fully cope with me defining my
own specialization of std::optional. I hoped this was just an
implementation bug and filed an issue with LLVM about it, [3], which
contains a code example and my proposed solution (see also on
[Godbolt]), but someone else pointed out that my proposed solution
also has an edge case. So as far as I can tell right now, it seems
impossible to implement std::optional<T>::transform while using only
the standard interface of the other specialization std::optional<U>.
If this really is the case, then the standard seems to have
inadvertently prohibited program-defined specializations of
std::optional with the addition of std::optional<T>::transform. I'm
hoping to get more eyes on this question. If someone in this list
could come up with a way to implement std::optional<T>::transform in a
way that permits program-defined specializations (or say with more
certainty that it's in fact not possible), that'd be great. Have I
found a standard defect?
- Rasheeq Azad
[1a]: https://github.com/gcc-mirror/gcc/blob/ffa98429b93934be87f58bc3af481a69310aedaf/libstdc%2B%2B-v3/include/std/optional#L97
[1b]: https://github.com/gcc-mirror/gcc/blob/ffa98429b93934be87f58bc3af481a69310aedaf/libstdc%2B%2B-v3/include/std/optional#L1490-L1493
[1c]: https://github.com/gcc-mirror/gcc/blob/ffa98429b93934be87f58bc3af481a69310aedaf/libstdc%2B%2B-v3/include/std/optional#L1391
[2a]: https://github.com/llvm/llvm-project/blob/9975cb166ea3925738abb8d0db0028e418315eda/libcxx/include/optional#L369
[2b]: https://github.com/llvm/llvm-project/blob/9975cb166ea3925738abb8d0db0028e418315eda/libcxx/include/optional#L925-L927
[2c]: https://github.com/llvm/llvm-project/blob/9975cb166ea3925738abb8d0db0028e418315eda/libcxx/include/optional#L1144
[3]: https://github.com/llvm/llvm-project/issues/172197
[Godbolt]: https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYgATKVpMGoZAFI9AIQuXSS%2BsgJ4BlRugDCqWgFcWDCaRuADJ4DJgAcr4ARpjEIACs8aQADqgKhM4Mnj5%2BAanpTgIhYZEsMXGJdpgOhQxCBEzEBNm%2B/lxVNZn1jQTFEdGxCUkKDU0tue0jPX2l5UMAlHao3sTI7BwWAMyhyD5YANRmm%2B78xCxMBEfYZhoAgls7e5iHx84jxJisVzf3etsMu28ByO7neoWA3zuPweAKeL08yVqYkh9zuuyYCgU%2BxYAE8APpRVBeQ4Adks%2BwA9BT9kx9sliKhgMRWABaLA0MLofYEHHJZ4ASWxeGACAI%2BwA7sYxUR9go%2Bcg8GI8AAvZ4jdAgECoRGZMT7U4/fb7ZAIRr7VRHax3ZLeKK0PDIECG/aYVTJe0KsW4glE2gQQnE1TzfYgc0QIOk8lmEkAEWd3oDfoTvosADY08GjjH9lh6ARMJbnQA/ZNeCCZsmkuObK2o25G13uh2Efba2IXEj7RPl40CEaR/YfAgrBjmy1V%2BP4xOtvnMojEMCQYNoBj96Pkocj7FT30QRfdoPzcfRuNQ2OFqF3fMsd0XAvHK7GoyY2UEDVanUCZHHUu0R/r513m8RwaSiJRBDxMV12NU1iFlRgnDCWgXmzPRj3PGtnW8BhMgHX86Q%2BcDLhrUCiMg0iEPQ6tySpWUmAAN0wLlaSiHF80OAAxDQzAATg4sxbniMxLE2RcfhtO0HSdO4jVoj56HoqVsUwMpYgUZ0VxGRs4O1JE/WDBhUFdNZERDCjBB7aCTw0vt8zdHTP2YP0GG8WhaF0yCDKM1QTLFUNdN1fSB2smSZz0iAAq/ZDNMuPRU0zTZs1zTB8wvOsjWvW9UuOdEXwAOgKgAVR8PgAR28PBCP2PAFDxGLiGApw7UwPF6JBX9SH2QqCrylEjRi7SXTdD0W0ipyIFCPFbzWSDOsKw44rTHqCGDUN6UwIiIHVTVTklYh0BBYrNmwCAVp6iso3PS9625FSsvvdxcqxIJOqe/YeqO7BB0wcrKo26ravqxq8Ga1r2p3LxOtCDIlVVYg8XtEYQSCb44rmnq%2Bt7Vc7PpIam09MLAomhgpqMGaCChnCnFh2IEZq4j3BR479loOaFvTOLltWgiNoQiBWdfd9dsaA7jk%2B075nO4Krpu2iV0YppwSxoDHBILFjC5VACAQWJ9mAEgcRzFKmDoLFUBYQh8wO67%2Btswbp1NWrFJ8TAexi/ZDOMzBTIA0KjU3YhRyYMCELyojQmqfYxMS8yCEg8sw4QiO/0w0KQpugb7P2IsxrESzKzwKgIEd1qxG8V35mDdaiLyksIf0qjoVCzKjGy9weT5Zg2H2fjmcz3GmG8GUCGZVdThYCAOPZtMqEzRbU/uDDax%2BWiEFQcV9gAKn5TeJWWWguTwG96DYQRuVHhRx/2CLtd11AFfcph0CxdILaMYgjyvO7W4ejvGFYZ4vcvoqzFD/OCvsbpTyoGlI0bY5ydiwLsP%2BEBB5EHmJZRacUBwB1HNtEALB76u1nuWRuZ5qI/BbneEEf8u6AMfP3OCqDUCC01LnFO7hfxXE1CPYwl8SATynmmGec9UyRiwukEw%2Bw5AoW%2BgQxidV6IfCoJBEEoR6KoAANYtUIq5OODMOKdU4fPa4x0YHVSLiXZ25dywXWdP7FKW48FsJBHIK4xNSZMDWJ1MBEAzDxGsIteI2YWSPmkRAo0ETvrDkDiwkAajNGuzwcLfaIIgHUEWDzIiR4F6RJPJXMxJ4XS0CUFExxb5WGOW/O4Vxx0SEL3Tj8UIXoTYMHzrWI0TjKnsM4czMoW1ylxJJtNTAnUR7l2ye02Jzifz10fGUPQMiyh5R4WPfhvi4q/gqe2eci4JlNxup0vSII8FghMI%2BKgLAoIxyWSsvhZxfH%2BL8TGFBQ9mHuzTGUC6pSYlJP4RcdZaEyTWXiO4BgFgDBdl3J8iZVY9mhULtQS5wY8FoCHvCEEW8LnEXJNUEpKLlhXPcBi8FwciJ%2BNBeCtKgEBnTPcImR8qAoiLKiMsi%2B491mpk2R%2BbZnZExwtltSW47gADSi5r72iiOYKwNgpldMOlwkAtyr41W5DrVsVAqBuFiJ/A5NK5UzJ9F4OZURNgyMZay3h7K/HWCCf6X0XYvk4O3Iav0UQYV5KpbGDgixaCcHiLwfwHAtCkFQJwIl0qrCymWKsZ4Ww9C8AIJob1iwdZP0GOWUgGiQCpk2HlRIqY9AaAAByphJBoDQPFEhcCSL6jgkheAsAkOW0ggbg2ho4LwBQIANCkETUG71pA4CwCQK6TAyBXlkAoCg4gwAFDKGMNUIQa9xSBp4KQNAN46AXEyPOpCS716tt4Bu5IdBBjohMJBBqDANHrvNie%2BgxBwgAM4Eeu9p7iAAHkh77pXUmwIqgx23BnV2jt/6x31HwIG3g/BBAiDEOwKQMhBCKBUOoftpBdDtCMCYFANgbCGBBl2pcIbHIgZZOqLMUqAmWD0MgfY5G3wSqzBKqjNheCEOIMQPAWAiMZqvU4NghVfS8cWAoaNax9B2DfKEXdi7l2roTR8dgPbxTMmSJwHgPq/UBr/e27AAHx3znNCWlkqZJBPmMMAa%2BYzr3BggOG6jnVcCEE7HG%2BYCak2V0zSATYqY8qSEkJsEkPEuCbD0DxHiGgAtFprZwetLbdMvrsN23tnmtMcHjQl9D7aPP9q8wrdILhJBAA%3D%3D
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
--
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
--
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
--
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
--
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
--
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
--