使用 Y 组合器的空参数包的模板替换失败
Template substitution failure with empty parameter pack using a Y-combinator
我正在尝试创建一个函数,该函数将使用 boost::asio::posix::stream_descriptor
从管道读取到缓冲区。我使用 async_read_some
而不是 boost::asio::async_read
,因为一旦读取了一大块数据,立即得到通知对我来说很重要。从管道读取数据后我想做的是
- 移动我的缓冲区的写入指针
- 用新得到的数据做点什么
- 安排读取更多数据
我想复制尽可能少的代码,所以我最终得到了一个函数式编程的混乱,我很想知道为什么它不起作用。
asio::posix::stream_descriptor inputPipe{context, input.fd};
char buffer[2048]; // simple buffer for demonstration purposes
char* end = buffer + 2048;
char* writer = buffer;
// the interesting part
yCombinator([&](auto&& self_) {
inputPipe.async_read_some(asio::buffer(writer, end - writer), [&](boost::system::error_code errorCode_, size_t transferedCount_) -> void {
writer += transferedCount_;
// ... be something, go somewhere, do something, make things change ...
self_(self_); // self_ contains the async_read_some, so it schedules the next read
});
})();
我自豪地将 yCombinator
呈现为:
template<typename Fn>
constexpr auto yCombinator(Fn&& fn_) noexcept {
return [capture = std::tuple{std::forward<Fn>(fn_)}](auto&&... args_) constexpr noexcept(std::is_nothrow_invocable_v<Fn, decltype(args_)...>)->std::invoke_result_t<Fn, decltype(args_)...> {
return std::invoke(std::get<0>(capture), std::get<0>(capture), std::forward<decltype(args_)>(args_)...);
};
}
目前上述代码编译失败。 G++ 抱怨 candidate template ignored: substitution failure [with args_:auto = <>]: no type named 'type' in 'std::invoke_result<(lambda at redacted.cpp:80:21)>'
。我知道这与从 yCombinator
编辑 return 的 lambda 的尾部 return 类型有关。我想问题可能是 args_
是一个空参数包,但我不确定如何处理它。但与此同时,如果这是问题所在,那么为什么 std::is_nothrow_invocable_v
特征看起来一切正常?
您有几个问题:
首先,returntype/noexcept和函数体不匹配:
错过前者Fn
template<typename Fn>
constexpr auto yCombinator(Fn&& fn_) noexcept {
return [capture = std::tuple{std::forward<Fn>(fn_)}](auto&&... args_) constexpr
noexcept(std::is_nothrow_invocable_v<Fn, Fn, decltype(args_)...>)
// ^^
-> std::invoke_result_t<Fn, Fn, decltype(args_)...>
// ^^
{
return std::invoke(std::get<0>(capture),
std::get<0>(capture),
std::forward<decltype(args_)>(args_)...);
};
}
然后,要推断未提供的 return 类型,我们必须 "look" in the body,因此使用 self_
return 在我们推断之前输入。
解决方案是明确提供类型:
yCombinator([&](auto&& self_) -> void
// ^^^^^^^
{
// ...
self_(self_);
})();
我正在尝试创建一个函数,该函数将使用 boost::asio::posix::stream_descriptor
从管道读取到缓冲区。我使用 async_read_some
而不是 boost::asio::async_read
,因为一旦读取了一大块数据,立即得到通知对我来说很重要。从管道读取数据后我想做的是
- 移动我的缓冲区的写入指针
- 用新得到的数据做点什么
- 安排读取更多数据
我想复制尽可能少的代码,所以我最终得到了一个函数式编程的混乱,我很想知道为什么它不起作用。
asio::posix::stream_descriptor inputPipe{context, input.fd};
char buffer[2048]; // simple buffer for demonstration purposes
char* end = buffer + 2048;
char* writer = buffer;
// the interesting part
yCombinator([&](auto&& self_) {
inputPipe.async_read_some(asio::buffer(writer, end - writer), [&](boost::system::error_code errorCode_, size_t transferedCount_) -> void {
writer += transferedCount_;
// ... be something, go somewhere, do something, make things change ...
self_(self_); // self_ contains the async_read_some, so it schedules the next read
});
})();
我自豪地将 yCombinator
呈现为:
template<typename Fn>
constexpr auto yCombinator(Fn&& fn_) noexcept {
return [capture = std::tuple{std::forward<Fn>(fn_)}](auto&&... args_) constexpr noexcept(std::is_nothrow_invocable_v<Fn, decltype(args_)...>)->std::invoke_result_t<Fn, decltype(args_)...> {
return std::invoke(std::get<0>(capture), std::get<0>(capture), std::forward<decltype(args_)>(args_)...);
};
}
目前上述代码编译失败。 G++ 抱怨 candidate template ignored: substitution failure [with args_:auto = <>]: no type named 'type' in 'std::invoke_result<(lambda at redacted.cpp:80:21)>'
。我知道这与从 yCombinator
编辑 return 的 lambda 的尾部 return 类型有关。我想问题可能是 args_
是一个空参数包,但我不确定如何处理它。但与此同时,如果这是问题所在,那么为什么 std::is_nothrow_invocable_v
特征看起来一切正常?
您有几个问题:
首先,returntype/noexcept和函数体不匹配:
错过前者Fn
template<typename Fn>
constexpr auto yCombinator(Fn&& fn_) noexcept {
return [capture = std::tuple{std::forward<Fn>(fn_)}](auto&&... args_) constexpr
noexcept(std::is_nothrow_invocable_v<Fn, Fn, decltype(args_)...>)
// ^^
-> std::invoke_result_t<Fn, Fn, decltype(args_)...>
// ^^
{
return std::invoke(std::get<0>(capture),
std::get<0>(capture),
std::forward<decltype(args_)>(args_)...);
};
}
然后,要推断未提供的 return 类型,我们必须 "look" in the body,因此使用 self_
return 在我们推断之前输入。
解决方案是明确提供类型:
yCombinator([&](auto&& self_) -> void
// ^^^^^^^
{
// ...
self_(self_);
})();