1

I'm stuck with a compilation problem. I do not understand why the following code does not compile:

#include <functional>

namespace async {

template<class ...T>
using Callback = std::function<void(const std::string& result, T ...args)>;

template<class Signature>
class Function;

template<class Res, class ...Args>
class Function<Res(Args...)>
{
    std::function<void(Args ...args, const Callback<Res>&)> m_function;
public:
    Function(std::function<void(Args ...args, const Callback<Res>&)>&& function) : m_function(std::move(function)) {}
    Function& operator=(std::function<void(Args ...args, const Callback<Res>&)>&& function) {m_function = std::move(function); return *this;}
    void operator()(Args... args, const Callback<Res>& callback) const {m_function(args..., callback);}
};

}

async::Function<int(int)> getF()
{
    return [](int i, const async::Callback<int> callback)
    {
        callback("", i);
    };
}

int main(int argc, char** argv)
{
    auto f0 = getF();
    return 0;
}

gcc says:

In function ‘async::Function getF()’: error: could not convert ‘getF()::__lambda0{}’ from ‘getF()::__lambda0’ to ‘async::Function’

icc says:

error: no suitable user-defined conversion from "lambda [](int, async::Callback)->void" to "async::Function" exists

Now if I replace

    return [](int i, const async::Callback<int> callback)
    {
        callback("", i);
    };

by

    return async::Function<int(int)>([](int i, const async::Callback<int> callback)
    {
        callback("", i);
    });

Then it works. Why to I need to cast explicitely and how to avoid this?


A simpler solution would be to replace the class Function by something like

template<class Signature>
using Function = std::nullptr_t;

template<class Res, class ...Args>
using Function<Res(Args...)> = std::function<void(Args ...args, const Callback<Res>&)>;

But the specialization with <Res(Args...)> does not compile...

0

1 Answer 1

7

There's no Function constructor that accepts a lambda. There is one that accepts an std::function, and there's also an std::function constructor that accepts a lambda, but C++ will never combine two implicit user-defined conversions for you.

The easiest way to define the needed constructor is

template <class T>
Function (T&& t) : m_function(std::forward<T>(t)) {}
Sign up to request clarification or add additional context in comments.

1 Comment

@SimonKraemer one could also remove async::Function altogether and use naked std::function instead...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.