C++ 绑定到包含多个std::函数类型的std::variant
我正在使用回调函数,希望通过签名不同的C++ 绑定到包含多个std::函数类型的std::variant,c++,c++17,std-function,std-variant,C++,C++17,Std Function,Std Variant,我正在使用回调函数,希望通过签名不同的std::bind注册多个函数(尽管它们都返回void)。将std::bind的结果分配给std::variant会产生“转换为非标量类型”错误。这是一个模棱两可的错误吗?我可以向编译器提供更多信息吗 删除std::bind(允许赋值)不是一个选项,因为我希望使用一些 模板 无效寄存器(函数和函数、参数和…参数) { 多个函数类型的变量=std::bind(f,args…); } 例如: std::variant<std::function<
std::bind
注册多个函数(尽管它们都返回void
)。将std::bind
的结果分配给std::variant
会产生“转换为非标量类型”错误。这是一个模棱两可的错误吗?我可以向编译器提供更多信息吗
删除std::bind
(允许赋值)不是一个选项,因为我希望使用一些
模板
无效寄存器(函数和函数、参数和…参数)
{
多个函数类型的变量=std::bind(f,args…);
}
例如:
std::variant<std::function<void()>, std::function<void(int)>> v =
std::bind([]() noexcept {});
std::variant v=std::bind([]()noexcept{});
有效,但是
std::variant v=std::bind([]()noexcept{});
不会,但我希望它编译成包含std::function
的std::variant
在GCC 7.4.0中,我在-std=c++17
中遇到以下编译错误:
error: conversion from ‘std::_Bind_helper<false, main(int, char**)::<lambda()> >::type {aka std::_Bind<main(int, char**)::<lambda()>()>}’ to non-scalar type ‘std::variant<std::function<void()>, std::function<void(int)> >’ requested
std::variant<std::function<void()>, std::function<void(int)>> v = std::bind([]() noexcept {});
错误:请求将“std::_Bind_helper::type{aka std::_Bind}”转换为非标量类型“std::variant”
std::variant v=std::bind([]()noexcept{});
std::bind
返回满足特定要求的未指定对象,但不允许基于签名区分函数类型。初始化
std::variant<std::function<void()>, std::function<void(int)>> v =
std::bind([]() noexcept {});
原因是,
std::bind
产生了与std::function
不同的类型(它是一种未指定/可调用的类型),因此在可转换时,它是不明确的。std::bind的一个特性是它使用额外参数所做的。考虑:
int f(int i) { return i + 1; }
auto bound_f = std::bind(f, 42);
bound\u f()
调用f(42)
,它给出43
。但是,bound\u f(“hello”)
和bound\u f(2.0,'3',std::vector{4,5,6})
也给出了43
。将忽略调用站点上没有关联占位符的所有参数
这里的意义在于,是可发票的
对于所有类型集都是正确的Args…
回到你的例子:
std::variant<std::function<void()>, std::function<void(int)>> v =
std::bind([]() noexcept {});
这很好,因为lambda只可调用,没有参数,所以只有一种选择是可行的。lambda不只是删除未使用的参数
这概括为:
template <typename Function, typename... Args>
void register(Function &&f, Args &&... args)
{
variant_of_multiple_func_types =
[f=std::forward<Function>(f), args=std::make_tuple(std::forward<Args>(args)...)]{
return std::apply(f, args);
});
}
模板
无效寄存器(函数和函数、参数和…参数)
{
多种函数类型的变体=
[f=std::forward(f),args=std::make_tuple(std::forward(args)…)]{
返回标准::应用(f,参数);
});
}
但是如果你想在这里传递占位符,这是行不通的。这实际上取决于您的更大设计,这里的正确解决方案可能是什么 您可以使用c++20,它将编译:
#include <functional>
#include <variant>
int main()
{
std::variant<std::function<void()>, std::function<void(int)>> v = std::bind_front([]() noexcept {});
std::get<std::function<void()>>(v)();
}
#包括
#包括
int main()
{
std::variant v=std::bind_front([]()noexcept{});
std::get(v)();
}
根据:
此函数用于替换std::bind
。与std::bind
不同,它不支持任意参数重新排列,并且对嵌套的绑定表达式或std::reference_包装器
s没有特殊处理。另一方面,它关注调用包装器对象的值类别,并传播底层调用运算符的异常规范
关于一个半相关的注释:为什么必须在工作示例中为lambda指定
noexcept
,以便编译通过?您能否通过“为什么必须在工作示例中为lambda指定noexcept
”来解释您的观点?。在使用相同的编译器和标志时,省略noexcept
仍然有效。为什么对lambda使用std::bind
<当lambda无法使用时,code>std::bind非常有用。在您的代码中,std::bind
只是过时了。std::bind([]()noexcept{})(“lot”、“of”、“unused”、“parameter”)
是有效的。您可以向bind对象传递任意数量的参数,它主要是place\u holder
(std::bind([](int){/*..*/},place\u holder::\u 5)
)所需的。@Jonas,哎呀,我错过了启用大多数警告的机会。编译失败,因为<代码> -WrOrr= No.<代码>。Jason Turner最近讨论了他在代码中重新实现代码< BdIdFrange >和C++每周的尝试。代替C++20的可用性可能很有趣。在我们故意不使用任何额外参数的情况下使用bind\u front
是很奇怪的。我们正在使用bind\u-front(f)
其中f
可以正常工作。@Jonas是的,但他的工具不能用于这种情况,因为他返回的是可变模板lambda。
std::variant<std::function<void()>, std::function<void(int)>> v =
[]() noexcept {};
template <typename Function, typename... Args>
void register(Function &&f, Args &&... args)
{
variant_of_multiple_func_types =
[f=std::forward<Function>(f), args=std::make_tuple(std::forward<Args>(args)...)]{
return std::apply(f, args);
});
}
#include <functional>
#include <variant>
int main()
{
std::variant<std::function<void()>, std::function<void(int)>> v = std::bind_front([]() noexcept {});
std::get<std::function<void()>>(v)();
}