我正在写Boost。Asio风格的异步函数,它接受CompletionToken
参数。参数可以是函数,函数对象,lambda表达式,future,waitable等等。CompletionToken
是模板参数。如果我不限制参数,函数可能匹配意外参数,如int
。所以我想用std::enable_if
写一些限制。(我的环境是C++17)。
如果CompletionToken
带参数,那么我可以使用std::is_invocable
进行检查。
请参见示例代码中的f1
。
但是,我遇到了一个问题,如果CompletionToken
不带参数,那么boost::asio::use_future
就会出错。
请参见示例代码中的f2
。
经过一些尝试和错误,我得到了我的解决方案。这是连接std::is_invocable
和use_future_t
检查或(||
)。
请参见示例代码中的f3
。
另外,我不确定Boost.Asio支持的其他特性(例如use_awaitable_t)是否需要类似的直接匹配检查。
我试着找到Boost。Asio提供类型特征或 predicate ,如is_completion_token
,但我找不到。
有没有更好的方法来检查CompletionToken
?
Godbolt链接https://godbolt.org/z/sPeMo1GEK
完整代码:
#include <type_traits>
#include <boost/asio.hpp>
// Callable T takes one argument
template <
typename T,
std::enable_if_t<std::is_invocable_v<T, int>>* = nullptr
>
void f1(T) {
}
// Callable T takes no argument
template <
typename T,
std::enable_if_t<std::is_invocable_v<T>>* = nullptr
>
void f2(T) {
}
template <template <typename...> typename, typename>
struct is_instance_of : std::false_type {};
template <template <typename...> typename T, typename U>
struct is_instance_of<T, T<U>> : std::true_type {};
// Callable T takes no argument
template <
typename T,
std::enable_if_t<
std::is_invocable_v<T> ||
is_instance_of<boost::asio::use_future_t, T>::value
>* = nullptr
>
void f3(T) {
}
int main() {
// no error
f1([](int){});
f1(boost::asio::use_future);
// same rule as f1 but use_future got compile error
f2([](){});
f2(boost::asio::use_future); // error
// a little complecated typechecking, then no error
f3([](){});
f3(boost::asio::use_future);
}
输出:
Output of x86-64 clang 13.0.1 (Compiler #1)
<source>:45:5: error: no matching function for call to 'f2'
f2(boost::asio::use_future); // error
^~
<source>:17:6: note: candidate template ignored: requirement 'std::is_invocable_v<boost::asio::use_future_t<std::allocator<void>>>' was not satisfied [with T = boost::asio::use_future_t<>]
void f2(T) {
^
1 error generated.
1条答案
按热度按时间toe950271#
如果你有c++20的概念,请看下面。否则,请继续阅读。
当您希望使用Asio正确实现异步结果协议时,可以使用
async_result
特征,或者这里介绍的async_initiate
。这应该是SFINAE的可靠密钥。
async_result
的模板参数包括标记 * 和 * 完成签名:Live On Compiler Explorer
已打印
C20概念
现在请记住,由于部分模板示例化,上面的代码“太松散”了。
async_result
的一些部分实际上没有被使用。这意味着f2(cb1);
will actually compile。链接的文档甚至包括C20
completion_token_for<Sig>
概念,让您可以毫不费力地做到精确:******否则
在实践中,您将始终遵循Asio配方,这保证了所有部件都被使用。
示例: