0

Can anyone figure out how to make this compile ?

I'm trying to wrap a lambda in another function that does something (here printing "you know what") + calling the lambda.

Best would be to have automatic template parameters deduction.

#include <iostream>
#include <functional>
#include <utility>

void youKnowWhat(const std::function<void()>&& fun)
{
    std::cout << "You know what ?" << std::endl;
    fun();
}

template <typename... Args>
auto youKnowWhatSomething(const std::function<void(Args...)>&& fun)
{
    return [fun{std::move(fun)}](Args... args)
        {
            youKnowWhat(std::bind(fun, std::forward<Args>(args)...));
        };
}

int main()
{
    const auto imHavingSomething([](const std::string& s){
        std::cout << "Im having " << s << std::endl;
    });

    const auto youKnowWhatImHavingSomething(youKnowWhatSomething(std::move(imHavingSomething)));
    youKnowWhatImHavingSomething("fun with templates");
    youKnowWhatImHavingSomething("headaches");
}

2 Answers2

1

Will this work for you? I've (basically) removed the const from const ... &&, and added a template parameter to the function youKnowWhatSomething. The lambda is no longer declared as const in main.

#include <iostream>
#include <functional>
#include <utility>

void youKnowWhat(const std::function<void()>& fun)
{
    std::cout << "You know what ?" << std::endl;
    fun();
}

template<typename function_t, typename... Args>
auto youKnowWhatSomething(function_t&& fun)
{
    return [fun{std::move(fun)}](Args... args)
        {
            youKnowWhat(std::bind(fun, std::forward<Args>(args)...));
        };
}

int main() {
    auto imHavingSomething = [](std::string s) {
        std::cout << "Im having " << s << std::endl;
    };

    const auto youKnowWhatImHavingSomething =
        youKnowWhatSomething<decltype(imHavingSomething), std::string>
        (std::move(imHavingSomething));

    youKnowWhatImHavingSomething("fun with templates");
    youKnowWhatImHavingSomething("headaches");
}
1

How about

#include <iostream>
#include <functional>
#include <utility>

template <typename F>
void youKnowWhat(F&& fun)
{
    std::cout << "You know what ?" << std::endl;
    fun();
}

template <typename F>
auto youKnowWhatSomething(F&& fun)
{
    return [fun{std::move(fun)}](auto&&... args) -> decltype(fun(std::forward<decltype(args)>(args)...), void())
        {
            youKnowWhat([&](){fun(std::forward<decltype(args)>(args)...); });
        };
}

int main()
{
    const auto imHavingSomething([](std::string s){
        std::cout << "Im having " << s << std::endl;
    });

    const auto youKnowWhatImHavingSomething(youKnowWhatSomething(imHavingSomething));
    youKnowWhatImHavingSomething("fun with templates");
    youKnowWhatImHavingSomething("headaches");
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Thanks ! I changed the code just to keep using std::bind inside, it also works. I don't understand what is the `void` doing in `decltype(fun(std::forward(args)...), void())` ? – Adrien Grosjean Mar 04 '22 at 13:52
  • 1
    I use `decltype` for SFINAE, last `void()` is to tell return type is `void`. You might drop the trailling return type for simplicity if wanted. – Jarod42 Mar 04 '22 at 13:58
  • I came across an issue with the above version : `auto... args` should be `auto&&... args` otherwise if the wrapped function takes a reference it makes a copy instead – Adrien Grosjean Mar 24 '22 at 09:52
  • 1
    @AdrienGrosjean: Version improved. – Jarod42 Mar 24 '22 at 12:44