Home > Software design >  Question about custom conversion of "lambda []void ()->void"
Question about custom conversion of "lambda []void ()->void"

Time:05-27

TestCase2 and TestCase3 can compile normally. However, in TestCase1 I get the following error:

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

Why am I getting this error? I want to know how to solve it.

#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()>>([]() {});
}

CodePudding user response:

Why am I getting this error?

The lambda []() {} is not the same as std::function<void()>. That means

decltype([]() {}) != std::function<void()>

and it has to be implicitly or explicitly converted.

At the line

EventHandler TestCase1 = []() {};

copy initialization take place, where compiler first has to convert the lambda to a std::function<void()> and then a EventHandler object. Compiler can not do double implicit conventions.

Therefore, you need to be explicit here, like in TestCase3 for instance.


I want to know how to solve it.

One way is to provide a templated constructor (if you willing to)

#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 }
    // { ... }
};

Now you can

EventHandler TestCase1 = []() {}; // works

Demo

CodePudding user response:

You can't assign a lambda directly to an EventHandler, there is no such conversion. Instead, you can invoke the EventHandler's constructor by adding curly braces, which will initialize the std::function with the lambda.

EventHandler TestCase1 = {[]() {}};

CodePudding user response:

Case 1

Here we consider the statement:

EventHandler TestCase1 = []() {};//this is copy initialization

the above statement uses copy initialization.

And from copy initialization's documentation:

In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.

And as EventHandler can't be directly produced from the initializer lambda on the right hand side, the first case of TestCase1 isn't allowed in accordance wirh the above quoted statement.


Case 2

Here we consider the statement,

EventHandler TestCase2([]() {});//this is direct initialization

the above uses direct initialization and since there is an implicit conversion available(using the converting constructor), this time it is allowed according to the above quoted statement.

  • Related