Reputation: 679
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
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.
*/
Upvotes: 2