error: conversion from 'main()::<lambda()>' to non-scalar type 'function<void()>' requested

114 Views Asked by At

In the following snippet I try to convert a lambda to my own function object, constraining it with a concept based on the invocable_r type trait. Yet gcc rejects it.

Demo

#include <concepts>
#include <cstdio>


template <typename Fn, typename R, typename... Args>
concept invocable_r = std::is_invocable_r<R, Fn, Args...>::value;

template <typename R, typename... Args>
class function
{
    template <invocable_r<R, Args...> Cb>
    function(Cb fn) {
        printf("Converting constructor invoked!\n");
    }

};

int main()
{
    function<void()> hello = [](){};
}

Error:

error: conversion from 'main()::<lambda()>' to non-scalar type 'function<void()>' requested

I can't seem to find the issue. What's wrong?

1

There are 1 best solutions below

3
On

You defined template of function wrong. Your version accepts multiple arguments, when infarct you wish to have one argument of specific type.

You need to use template specialization. Also you have forgotten about public::

#include <concepts>
#include <cstdio>


template <typename Fn, typename R, typename... Args>
concept invocable_r = std::is_invocable_r<R, Fn, Args...>::value;

template <typename T>
class function;

template <typename R, typename... Args>
class function<R(Args...)>
{
public:
    template <invocable_r<R, Args...> Cb>
    function(Cb fn) {
        printf("Copy constructor invoked!\n");
    }

};

int main()
{
    function<void()> hello = [](){};
}

https://godbolt.org/z/xrvr3sMj3

Your version must be used this way:

int main()
{
    function<void> hello = [](){};
}

https://godbolt.org/z/xvGd1s4az

BTW there is std::invocable concept, so you have introduced something what is already covered by std.