How to define template parameters for a generic lambda argument? [duplicate]

故事扮演 提交于 2019-12-02 04:12:21

As already pointed out by @cpplearner in the comments above, the reason why this won't work is explained in detail here: Constructing std::function argument from lambda.

If your Sequence is already a template, there should be no reason to require the callable for your map function to be passed in the form of an std::function. At least, I seem unable to come up with a reason that could justify doing this. std::function is generally not free to construct or call, and also can inhibit inlining. Best avoid it unless you really need the capability to store arbitrary callables for later use. Simply take a forwarding reference, e.g.:

template <typename F>
auto map(F&& f) const;

You should be able to deduce the result type of whatever invoking f on an element of your sequence ends up producing, e.g., via

decltype(f(std::declval<T>()))

Furthermore, don't just return a raw pointer to a new Sequence. Use an std::unique_ptr.

Putting it all together, your map function could look something like this:

template <typename F>
auto map(F&& f) const
{
    using output_element_type = decltype(f(std::declval<T>()));

    auto sequence = std::make_unique<Sequence<output_element_type>>();

    for (const T& element : *this)
        sequence->push(f(element));

    return sequence;
}

Ignoring the const problem, you have a sort of chicken-and-egg problem.

It's true that your lambda can be converted to a std::function<std::uint32_t(std::unit32_t)>.

But it's also true that the lambda isn't a std::function<std::uint32_t(std::unit32_t)> so the compiler can't deduce A.

And if the compiler can't deduce A, can't convert the lambda to std::function<A(T)>.

You obviously can explicit the correct std::function type calling map()

a.map(std::function<std::uint32_t(std::uint32_t)>{[]( uint32_t c ) -> uint32_t {
    return c * c;
}});

and, taking in count that you're using C++17 (so you can use the deduction guides for std::function) also deducing the template parameters for std::function

a.map(std::function{[]( uint32_t c ) -> uint32_t {
    return c * c;
}});

but, using again the template deduction guides for std::function, what about writing mat() to accept a simply callable and deducing A from it?

I mean... what about something as follows?

template <typename F>
auto map( F && func ) const {
    using A = typename decltype(std::function{std::forward<F>(func)})::result_type;

    auto sequence = new Sequence< A >;
    for ( const T& element : *this ) {
        sequence->push( std::forward<F>(func)( element ) );
    }
    return *sequence;
}

(caution: code not tested).

You can also deduce A, without std::function deduction guides (so before C++17), as suggested by Michael Kenzel.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!