Tmp*_*plt 10 c++ std-function c++17 std-variant
I'm playing around with callback functions and wish to register multiple functions via std::bind that differ in signatures (altough they all return void). Assigning the result of the std::bind to the std::variant yields in a "conversion to non-scalar type" error. Is it an ambiguity error? Can I provide the compiler with more information?
Dropping the std::bind (which allows the assignment) is not an option as I wish to register the callbacks using some
template <typename Function, typename... Args>
void register(Function &&f, Args &&... args)
{
variant_of_multiple_func_types = std::bind(f, args...);
}
Run Code Online (Sandbox Code Playgroud)
For example:
std::variant<std::function<void()>, int> v = std::bind([]() noexcept {});
Run Code Online (Sandbox Code Playgroud)
works, but
std::variant<std::function<void()>, std::function<void(int)>> v = std::bind([]() noexcept {});
Run Code Online (Sandbox Code Playgroud)
does not, while I expect it to compile into a std::variant containing a std::function<void()>.
I get the following compilation error in GCC 7.4.0 with -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 {});
Run Code Online (Sandbox Code Playgroud)
std::bind returns an unspecified object that satisfies certain requirements, but doesn't allow for a distinction between function types based on a signature. The initialization
std::variant<std::function<void()>, std::function<void(int)>> v =
std::bind([]() noexcept {});
Run Code Online (Sandbox Code Playgroud)
is simply ambiguous, same as
std::variant<int, int> v = 42; // Error, don't know which one
Run Code Online (Sandbox Code Playgroud)
You can be explicit about the type you intend to instantiate, e.g.
std::variant<std::function<void()>, std::function<void(int)>> v =
std::function<void()>{std::bind([]() noexcept {})};
Run Code Online (Sandbox Code Playgroud)
This cries for some type aliases, but basically works. A better alternative might be to avoid std::bind and instead use lambdas, too. Example:
template <typename Function, typename... Args>
void registerFunc(Function &&f, Args &&... args)
{
variant_of_multiple_func_types =
[&](){ std::forward<Function>(f)(std::forward<Args>(args)...); };
}
Run Code Online (Sandbox Code Playgroud)
您可以使用c ++ 20 std::bind_front,它将编译:
#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)();
}
Run Code Online (Sandbox Code Playgroud)
根据cppreference:
此功能旨在替代
std::bind。不同于std::bind,它不支持任意参数重排,并且对嵌套的bind-expressions或std::reference_wrappers 没有特殊的处理。另一方面,它注意调用包装对象的值类别,并传播基础调用操作程序的异常规范。