关于“lambda []void ()->void”自定义转换的问题

Sit*_*myu 9 c++ lambda class c++11 std-function

TestCase2并且TestCase3可以正常编译。但是,TestCase1我收到以下错误:

E0312, Custom conversion from "lambda []void ()->void" to
       "EventHandler" is not appropriate.
Run Code Online (Sandbox Code Playgroud)

为什么我会收到此错误?我想知道如何解决。

#include <functional>
#include <iostream>

class EventHandler
{
    std::function<void()> _func;

public:
    int id;
    static int counter;

    EventHandler() : id{ 0 } {}
    EventHandler(const std::function<void()>& func) : _func{ func }
    {
        id = ++EventHandler::counter;
    }
};

int EventHandler::counter = 0;

int main()
{
    EventHandler TestCase1 = []() {};
    EventHandler TestCase2([]() {});
    EventHandler TestCase3 = static_cast<std::function<void()>>([]() {});
}
Run Code Online (Sandbox Code Playgroud)

JeJ*_*eJo 14

为什么我会收到此错误?

lambda[]() {}与 不同std::function<void()>。这意味着

decltype([]() {}) != std::function<void()>
Run Code Online (Sandbox Code Playgroud)

并且必须隐式或显式转换它。

在行

EventHandler TestCase1 = []() {};
Run Code Online (Sandbox Code Playgroud)

进行复制初始化,编译器首先必须将 lambda 转换为 a std::function<void()>,然后转换为EventHandler对象。编译器不能执行双重隐式约定。

因此,你需要在这里明确,就像在TestCase3例子中一样。


我想知道如何解决。

一种方法是提供模板化构造函数(如果您愿意)

#include <type_traits> // std::is_convertible_v

class EventHandler
{
    std::function<void()> _func;
public:

    template<typename Func> EventHandler(Func func)
        : _func{ func }
    {
        static_assert(std::is_convertible_v<Func, decltype(_func)>
                                            , "is not valid arg!");
        // ....
    }
    // or in C++20 with <concepts> header
    // template<typename Func> EventHandler(Func func)
    //     requires std::convertible_to<Func, decltype(_func)>
    //  : _func{ func }
    // { ... }
};
Run Code Online (Sandbox Code Playgroud)

现在你可以

EventHandler TestCase1 = []() {}; // works
Run Code Online (Sandbox Code Playgroud)

演示