Michal
Michal

Reputation: 679

Concatenate function calls with a template lambda C++20

I have a template function that concatenates function calls:

template<typename Callable, typename... Callables>
decltype(auto) concat_callable(Callable callable, Callables... callables)
{
    if constexpr (sizeof...(callables) > 0) {
        return [=]
        <typename... Args>
        (Args&&... args) {
            return callable(concat_callable(callables...)(std::forward<Args>(args)...));
        };
    }
    else {
        return callable;
    }
}

I have the following functions that I want to call:

std::string& f_1(std::string& str)
{
    return str;
}

std::string& f_2(std::string& str)
{
    return str;
}

std::string& f_3(std::string& str)
{
    return str;
}

I want to call it like this:

std::string str{ "sample text" };
concat_callable(f_1, f_2, f_3)(str);

which is equivalent to:

f_1(f_2(f_3(str)));

but currently I am getting an error 'std::string &(std::string &)': cannot convert argument 1 from 'std::string' to 'std::string &'.

From some reason, it compiles fine when I use only two functions e.g.:

concat_callable(f_1, f_2)(str);

Any ideas how to fix it, please?

Upvotes: 0

Views: 83

Answers (1)

rafix07
rafix07

Reputation: 20969

Add -> decltype(auto) as trailing return type to lambda. Without this, reference from return type is discarded.

    return [=]
    <typename... Args>
    (Args&&... args) -> decltype(auto) {
        return callable(concat_callable(callables...)(std::forward<Args>(args)...));
    };

Invocation concat_callable with f1,f2 can be translated:

conact_callable(f1,f2)
    return f1(f2) 

This works fine, f1 takes string&, f2 returns reference.

But with three or more callables:

concact_callable(f1,f2,f3)
    return f1( concat_callable(f2,f3) )

    /*
    here is a problem because concat_callable discards reference
    from return type and temporary string cannot be bound to
    Lvalue reference.
    */

Demo

Upvotes: 2

Related Questions