Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 绑定到包含多个std::函数类型的std::variant_C++_C++17_Std Function_Std Variant - Fatal编程技术网

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)();
}