I have a stdexec::task whose environment type requires a query from the enclosing
environment, so that starting the task without that query is a compile error rather than
something that silently runs with a default value.
The consumer provides the query. This compiles and runs in every arrangement I tried
except one: when there is a let_value between starts_on and the task.
#include <stdexec/execution.hpp>
namespace ex = stdexec;
struct my_query_t {
static constexpr bool query(ex::forwarding_query_t) noexcept { return true; }
template <class Env>
auto operator()(const Env& env) const noexcept -> decltype(env.query(*this)) {
return env.query(*this);
}
};
inline constexpr my_query_t my_query{};
struct my_own_env {
template <class ParentEnv>
requires requires(const ParentEnv& parent) { my_query(parent); }
explicit my_own_env(const ParentEnv& parent) : value(my_query(parent)) {}
int value = -1;
};
struct my_task_env {
template <class ParentEnv>
using env_type = my_own_env;
explicit my_task_env(const my_own_env& own) noexcept : value(own.value) {}
auto query(my_query_t) const noexcept -> int { return value; }
int value;
};
auto child() -> ex::task<void, my_task_env> { co_return; }
int main() {
ex::run_loop loop;
auto sched = loop.get_scheduler();
auto q = ex::prop{my_query, 7};
ex::sync_wait(ex::starts_on(sched, ex::just() | ex::let_value(child)) |
ex::write_env(q));
}
g++ -std=c++26 -Iinclude -fsyntax-only repro.cpp
fails with:
include/stdexec/__detail/__task.hpp:440:34: error: no matching function for call to ‘my_own_env::my_own_env(<brace-enclosed initializer list>)’
440 | return __own_env_t<_Env>{};
| ^
clang 21.1.8 reports the same thing (no matching constructor for initialization of '__own_env_t<...>' at the same line).
Replacing only the last statement, keeping everything else, these all compile:
| variant |
result |
starts_on(sched, just() | let_value(child)) | write_env(q) |
fails |
on(sched, just() | let_value(child)) | write_env(q) |
fails |
starts_on(sched, child()) | write_env(q) |
compiles |
just() | let_value(child) | write_env(q) |
compiles |
continues_on(just() | let_value(child), sched) | write_env(q) |
compiles |
starts_on(sched, just() | let_value(child) | write_env(q)) |
compiles |
So the task sees the query when it is the direct child of starts_on, and when write_env
is applied inside starts_on, but not when a let_value sits between starts_on and the
task. Is the failing arrangement expected to work, or am I misusing env_type here?
Tested at f91f6363 with g++ 15.2.0 and clang 21.1.8, both -std=c++26.
I have a
stdexec::taskwhose environment type requires a query from the enclosingenvironment, so that starting the task without that query is a compile error rather than
something that silently runs with a default value.
The consumer provides the query. This compiles and runs in every arrangement I tried
except one: when there is a
let_valuebetweenstarts_onand the task.fails with:
clang 21.1.8 reports the same thing (
no matching constructor for initialization of '__own_env_t<...>'at the same line).Replacing only the last statement, keeping everything else, these all compile:
starts_on(sched, just() | let_value(child)) | write_env(q)on(sched, just() | let_value(child)) | write_env(q)starts_on(sched, child()) | write_env(q)just() | let_value(child) | write_env(q)continues_on(just() | let_value(child), sched) | write_env(q)starts_on(sched, just() | let_value(child) | write_env(q))So the task sees the query when it is the direct child of
starts_on, and whenwrite_envis applied inside
starts_on, but not when alet_valuesits betweenstarts_onand thetask. Is the failing arrangement expected to work, or am I misusing
env_typehere?Tested at
f91f6363with g++ 15.2.0 and clang 21.1.8, both-std=c++26.