Date: Mon, 25 May 2026 06:12:48 +0100
There is a pattern used sometimes in C++ where you pass a callable
instead of an object. This lets you 'pass' prvalue directly without
materializing an xvalue and moving from it:
template<class T>
struct my_optional {
template<class F>
T& emplace_result_of(F&& f) {
reset();
return ::new (storage) T(std::forward<F>(f)());
}
};
my_optional<std::atomic<int>> a;
m.emplace_result_of([]{ return std::atomic<int>{1}; });
I would like to propose a standardisation of this that achieves this
by doing something similar to automatically wrapping an expression in
a lambda.
`std::lazy<T>` (name to be changed): Special initialization rules,
when you initialize it, it is like you are initializing a T. It will
have a `T operator()() &&;` that when called will evaluate the
initializer. There is no lifetime extension for anything, as it is
supposed to work similarly to a lambda that has a default capture of
`&` and it is meant to be a function argument. Though in principle
there would be nothing stopping something like:
std::lazy<int> x = f(); // f is not called here
return std::move(x)(); // f is called
So for example:
template<class T>
struct my_optional {
T& emplace_lazy(std::lazy<T> x) {
reset();
return ::new (storage) T(std::move(x)());
}
};
my_optional<std::atomic<int>> m;
m.emplace_lazy(1);
This also has a use case for conditionally evaluating something, so
`assert()` could be implemented without a macro, or `logger.log(level,
expression)` could conditionally evaluate the expression based on the
runtime log level.
This could be seen as a potential footgun (operator() could be called
0, 1 or more times), but with the 'standard' use case of just perfect
forwarding, it should be safe enough (similar to how `f(std::move(x))`
might not actually move-from x). Having to call the operator() after
moving should allow existing compiler warnings about use-after-move to
fire.
Further extension is `std::lazy<T>` for a template parameter T
deducing as a non-reference for a prvalue argument and a lvalue or
rvalue reference for a glvalue argument, for forwarding value category
for prvalues better (as opposed to universal references which always
forward prvalues as xvalues).
I'm working on a proof-of-concept Clang implementation of this. I was
also wondering if there have been similar proposals for this in the
past? Sort of similar: <htttps://wg21.link/P2785R3>,
<https://wg21.link/P0573R2>
It will be specified as:
namespace std {
template<class T> class lazy {
public:
constexpr T operator()() &&;
};
}
+ a bunch of cases in [dcl.init] for specializations of (cv?)
std::lazy<T> (but not std::lazy<T>&)
And my implementation is going to have:
template<class T> class lazy {
T(* f)(void*); // Compiler will directly initialize
void* ctx;
public:
constexpr T operator()() && {
return f(ctx);
}
};
instead of an object. This lets you 'pass' prvalue directly without
materializing an xvalue and moving from it:
template<class T>
struct my_optional {
template<class F>
T& emplace_result_of(F&& f) {
reset();
return ::new (storage) T(std::forward<F>(f)());
}
};
my_optional<std::atomic<int>> a;
m.emplace_result_of([]{ return std::atomic<int>{1}; });
I would like to propose a standardisation of this that achieves this
by doing something similar to automatically wrapping an expression in
a lambda.
`std::lazy<T>` (name to be changed): Special initialization rules,
when you initialize it, it is like you are initializing a T. It will
have a `T operator()() &&;` that when called will evaluate the
initializer. There is no lifetime extension for anything, as it is
supposed to work similarly to a lambda that has a default capture of
`&` and it is meant to be a function argument. Though in principle
there would be nothing stopping something like:
std::lazy<int> x = f(); // f is not called here
return std::move(x)(); // f is called
So for example:
template<class T>
struct my_optional {
T& emplace_lazy(std::lazy<T> x) {
reset();
return ::new (storage) T(std::move(x)());
}
};
my_optional<std::atomic<int>> m;
m.emplace_lazy(1);
This also has a use case for conditionally evaluating something, so
`assert()` could be implemented without a macro, or `logger.log(level,
expression)` could conditionally evaluate the expression based on the
runtime log level.
This could be seen as a potential footgun (operator() could be called
0, 1 or more times), but with the 'standard' use case of just perfect
forwarding, it should be safe enough (similar to how `f(std::move(x))`
might not actually move-from x). Having to call the operator() after
moving should allow existing compiler warnings about use-after-move to
fire.
Further extension is `std::lazy<T>` for a template parameter T
deducing as a non-reference for a prvalue argument and a lvalue or
rvalue reference for a glvalue argument, for forwarding value category
for prvalues better (as opposed to universal references which always
forward prvalues as xvalues).
I'm working on a proof-of-concept Clang implementation of this. I was
also wondering if there have been similar proposals for this in the
past? Sort of similar: <htttps://wg21.link/P2785R3>,
<https://wg21.link/P0573R2>
It will be specified as:
namespace std {
template<class T> class lazy {
public:
constexpr T operator()() &&;
};
}
+ a bunch of cases in [dcl.init] for specializations of (cv?)
std::lazy<T> (but not std::lazy<T>&)
And my implementation is going to have:
template<class T> class lazy {
T(* f)(void*); // Compiler will directly initialize
void* ctx;
public:
constexpr T operator()() && {
return f(ctx);
}
};
Received on 2026-05-25 05:13:27
