How to create a variadic generic lambda? - c++

Since C++14 we can use generic lambdas:
auto generic_lambda = [] (auto param) {};
This basically means that its call operator is templated based on the parameters marked as auto.
The question is how to create a lambda that can accept a variadic number of parameters similarly to how a variadic function template would work ? If this is not possible what is the closest thing that could be used the same way ?
How would you store it ? Is it possible in a std::function ?

I am not sure what your intention is but instead of storing it in a std::function you can use the lambda itself to capture the params.
This is an example discussed on the boost mailing list. It is used in the boost::hana implementation
auto list = [](auto ...xs) {
return [=](auto access) { return access(xs...); };
};
auto head = [](auto xs) {
return xs([](auto first, auto ...rest) { return first; });
};
auto tail = [](auto xs) {
return xs([](auto first, auto ...rest) { return list(rest...); });
};
auto length = [](auto xs) {
return xs([](auto ...z) { return sizeof...(z); });
};
// etc...
// then use it like
auto three = length(list(1, '2', "3"));

Syntax
How do you create a variadic generic lambda ?
You can create a variadic generic lambda with the following syntax:
auto variadic_generic_lambda = [] (auto... param) {};
Basically you just add ... between auto (possibly ref qualified) and your parameter pack name.
So typically using universal references would give:
auto variadic_generic_lambda = [] (auto&&... param) {};
Usage
How do you use the parameters ?
You should consider the variadic generic parameter as having a template parameter pack type, because it is the case. This more or less implies that most if not all usage of those parameters will require templates one way or the other.
Here is a typical example:
#include <iostream>
void print(void)
{
}
template <typename First, typename ...Rest>
void print(const First& first, Rest&&... Args)
{
std::cout << first << std::endl;
print(Args...);
}
int main(void)
{
auto variadic_generic_lambda = [] (auto... param)
{
print(param...);
};
variadic_generic_lambda(42, "lol", 4.3);
}
Storage
How do you store a variadic generic lambda ?
You can either use auto to store a lambda in a variable of its own type, or you can store it in a std::function but you will only be able to call it with the fixed signature you gave to that std::function :
auto variadic_generic_lambda = [] (auto... param) {};
std::function<void(int, int)> func = variadic_generic_lambda;
func(42, 42); // Compiles
func("lol"); // Doesn't compile
What about collections of variadic generic lambdas ?
Since every lambda has a different type you cannot store their direct type in the usual homogeneous containers of the STL. The way it is done with non generic lambdas is to store them in a corresponding std::function which will have a fixed signature call and that won't restrain anything since your lambda is not generic in the first place and can only be invoked that way:
auto non_generic_lambda_1 = [] (int, char) {};
auto non_generic_lambda_2 = [] (int, char) {};
std::vector<std::function<void(int, char)>> vec;
vec.push_back(non_generic_lambda_1);
vec.push_back(non_generic_lambda_2);
As explained in the first part of this storage section if you can restrain yourself to a given fixed call signature then you can do the same with variadic generic lambdas.
If you can't you will need some form of heterogenous container like:
std::vector<boost::variant>
std::vector<boost::any>
boost::fusion::vector
See this question for an example of heterogenous container.
What else ?
For more general informations on lambdas and for details on the members generated and how to use the parameters within the lambda see:
http://en.cppreference.com/w/cpp/language/lambda
How does generic lambda work in C++14?
How to call a function on all variadic template args?
What is the easiest way to print a variadic parameter pack using std::ostream?

Consider this
#include <iostream>
namespace {
auto out_ = [] ( const auto & val_)
{
std::cout << val_;
return out_ ;
};
auto print = [](auto first_param, auto... params)
{
out_(first_param);
// if there are more params
if constexpr (sizeof...(params) > 0) {
// recurse
print(params...);
}
return print;
};
}
int main()
{
print("Hello ")("from ")("GCC ")(__VERSION__)(" !");
}
(wandbox here) This "print" lambda is:
Variadic
Recursive
Generic
Fast
And no templates in sight. (just underneath :) ) No C++ code that looks like radio noise. Simple, clean and most importantly:
Easy to maintain
No wonder "it feels like a new language".

Related

Variable type of template lambda (C++)

I'm implementing a lambda as variable.
In C++20 it works this way:
auto lambda = []<typename T>() -> const T& {
...
};
Now I want to store this kind of lambda function as a member variable of a struct:
struct A {
??? m_lambda;
A(??? lambda) : m_lambda(lambda) {}
};
Is there a way to do this?
You store any templated lambda the same ugly way you store ordinary ones:
constexpr auto lambda = []<typename T>() {};
struct Foo{
decltype(lambda) m_lambda;
Foo():m_lambda(lambda){}
};
This works because it is operator() that is actually templated, not the automatically-generated lambda type.
If you do not rely on inlining any calls to the lambda (for performance), you can store it in std::function<Ret(Args)> for correct signature.
std::function is also the only* option if the lambda cannot be defined before Foo as seems to be the case of your constructor.
struct A {
std::function<void()> m_lambda;
// Not a lambda per se.
A(std::function<void()> lambda) : m_lambda(std::move(lambda)) {}
};
The above is not a lambda exactly because it doesn't really make sense most of the time to take a lambda as parameter as each has a distinct type making the argument effectively redundant.
*One can always make A a class template and use CTAD for deduction, not sure you want to go that way though.
In c++20 you can do:
struct Foo
{
decltype([] <class T> () {/* ... */ }) m_lambda {};
};
That being said it doesn't make any sense to store a lambda as a data member. Lambdas cannot change so a method is the simple, preferred alternative.
Since your lambda is templated, you will need to contain the lambda directly in your object.
Fortunately, it's quite easy to do in C++20 (and C++17):
auto lambda = []<typename T>() -> const T& {
// ...
};
template<typename L> // <-- L is the lambda type
struct A {
L m_lambda;
A(L lambda) : m_lambda(lambda) {}
void foo() {
// Can call using many types using the template
int const& a = m_lambda.template operator()<int>();
float const& b = m_lambda.template operator()<float>();
}
};
int main() {
auto my_a = A{lambda}; // construct using the lambda and CTAD
my_a.foo();
}
If on the contrary you need A to only call one version of the template, you can wrap the lambda in another lambda:
struct A {
std::function<int const&()> m_lambda;
A(auto const& lambda) : m_lambda{
[lambda]{ return lambda.template operator()<int>(); }
} {}
void foo() {
// Can call and get a int const reference back
int const& a = m_lambda();
}
};

Call std::visit with passed lambdas

I have a struct that contains a variant.
I want to write a member function for that struct that should run code depending on which type variant currently holds.
However, I have issues making it compile.
I don't want to use more "template shenanigans" like using a separate struct to define operator(T&) since it pollutes the syntax even more.
Here is an example:
struct Data {
std::variant<int, double> var;
//Into this function,multiple lambdas should be passed for cases that the user wants to handle
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
std::visit(std::forward<Funcs>(funcs)...,var);
}
};
int main() {
Data d;
d.var = 4;
//variant holds int and lambda provided that takes int&, execute it:
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
d.var = 0.0;
//variant holds double but no lambda passed that takes a double, hence nothing happens:
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
}
and I even don't know what the compiler wants from me:
https://godbolt.org/z/oM4584anf
Your problem is that std::visit() needs a "visitor" that must handle every type of the std::variant.
However, I have issues making it compile. I don't want to use more "template shenanigans" like using a separate struct to define operator(T&) since it pollutes the syntax even more.
There is nothing complicated.
You can simply add a trivial struct (with deduction guide) as follows (and as proposed in the cppreference std::visit() page)
template<class... Ts> struct overloaded : Ts...
{ using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
Then, given that you want that your std::visit() return void, you can add, in your apply() method, a generic-do-nothing lambda
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
std::visit(overloaded{ // <-- pass through overloaded
[](auto const &){}, // <-- and add this generic lambda
std::forward<Funcs>(funcs)...},var);
}
Now the first apply() call
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
should compile calling the supplied lambda because is a better match (given that d contains an int) and the second call compile calling the do-nothing generic lambda, because the generic lambda is a better match for a double.

Is it possible to forward function calls with matching template type for a std::any-like container?

I haven't found a way to achieve what I want but I'm not knowledgeable enough to know if its impossible. Help would be appreciated.
The main data data container in our software behaves a bit like a std::variant or std::any: It has a base class BaseContainer that provides a type enum. The derived instance DataContainer holds the actual data in a typed tensor member variable. So a simplified example boils down to something like this:
BaseContainer* vContainer = new DataContainer<float>({1000000});
if (vContainer->getType() == DataTypes::FLOAT)
const Tensor<float>& vTensor = dynamic_cast<DataContainer<float>>(vContainer)->getData();
We have many methods that process data based on the underlying templated type and dimensions:
template<typename T>
void processData(const tensor<T>& aTensor, ...other arguments...);
The problem is, for every method like processData() that we want to call with a BaseContainer, we need to write a binding method that unravels the possible types to call the typed version of processData():
void processData(BaseContainer* aContainer) {
switch (vContainer->getType()) {
case DataTypes::INT8:
return processData(dynamic_cast<DataContainer<int8_t>>(vContainer)->getData());
case DataTypes::UINT8:
return processData(dynamic_cast<DataContainer<uint8_t>>(vContainer)->getData());
case DataTypes::INT16:
return processData(dynamic_cast<DataContainer<int16_t>>(vContainer)->getData());
case DataTypes::UINT16:
return processData(dynamic_cast<DataContainer<uint16_t>>(vContainer)->getData());
...
default:
throw(std::runtime_error("Type not supported"));
}
}
My question is: Is it possible to make a single "adapter" method (in any released version of c++) that can take a function (like processData()), a BaseContainer and potentially a list of arguments, and invoke the correct template binding of this function with the arguments?
I failed to bind a template function dynamically because I was not able to pass the name without the template type. Yet the template type would need to be dynamic based on the BaseContainer. But maybe there are other means to achieve what I want to do? I'm very curious about any solution, mostly also to extend my understanding, as long as the complexity of the solution is below writing hundreds of adapter methods.
If nothing else, would it be possible to generate the "adapter" methods using preprocessor macros?
You cannot pass overloads by name, but you can pass functor with overloaded operator() as generic lambda have.
So
template <typename F>
auto dispatch(BaseContainer& vContainer, F f) {
switch (vContainer.getType()) {
case DataTypes::INT8:
return f(dynamic_cast<DataContainer<int8_t>&>(vContainer).getData());
case DataTypes::UINT8:
return f(dynamic_cast<DataContainer<uint8_t>&>(vContainer).getData());
case DataTypes::INT16:
return f(dynamic_cast<DataContainer<int16_t>&>(vContainer).getData());
case DataTypes::UINT16:
return f(dynamic_cast<DataContainer<uint16_t>&>(vContainer).getData());
...
default:
throw (std::runtime_error("Type not supported"));
}
}
with usage
dispatch(vContainer, [](auto* data){ return processData(data); });
If you are willing to write a small wrapper class for each processData-like function, you could do something like this:
// One like this for each function.
struct ProcessDataWrapper {
template <typename... Args>
static auto run(Args&&... args) {
return processData(std::forward<Args>(args)...);
}
};
template <typename Wrapper>
auto ProcessGeneric(BaseContainer* aContainer) {
switch (vContainer->getType()) {
case DataTypes::INT8:
return Wrapper::run(dynamic_cast<DataContainer<int8_t>>(vContainer)->getData());
// ...
}
// Called as
ProcessGeneric<ProcessDataWrapper>(myContainer);
It is possible, but as the comments say, it might be worth conidering std::visit.
Here's a solution requiring c++17 that only requires two lines for each function template you want to wrap. You could use a simple macro to simplify the wrpping further.
The core idea is to have a cast function that maps from a DataType enum to the correspondng DataContainer and then to leverage c++17 fold expressions to wrap the switch statement in your code.
Here's the cast function, so we have exactly one place to map from DataType to the actiual DataContainer:
template<DataType t>
constexpr inline decltype(auto) cast(BaseContainer& c) {
if constexpr(t == INT) return static_cast<DataContainer<int>&>(c);
else if constexpr(t == FLOAT) return static_cast<DataContainer<float>&>(c);
... map all other enum values ...
}
This is rather a convenience helper to make the following code a bit more readable. The next code block uses the c++17 fold expression to dispatch the function based on the type of the container.
template<DataType... types>
auto dispatcher_impl = [](auto f) {
// NB: capture by value here only for sake of readbility.
return [=](BaseContainer& c, auto... args) {
([&]{ if(c.GetDataType() == types ) { std::invoke(f, cast<types>(c), args...); return true; } return false; }() || ...);
};
};
auto data_type_dispatcher = [](auto f) {
return dispatcher_impl<INT, FLOAT, ... other types here ...>(f);
};
The core idea is to wrap the function into a lambda that checks the DataContainer's DataType and calls the function only if it matches. The Fold expression over the || operator is used to unpack the DataTypes.
Usage example:
template<typename T>
void processData(DataContainer<T>& c, int arg) {
if constexpr(std::is_same_v<T, int>) std::cout << "int";
else if constexpr(std::is_same_v<T, float>) std::cout << "float";
std::cout << ", arg: " << arg << '\n';
}
// This needs to be done for each function:
auto pd = data_type_dispatcher([](auto& c, int arg) { processData(c, arg); });
int main() {
DataContainer<float> f;
DataContainer<int> i;
pd(f, 2); // prints float, 2
pd(i, 4); // prints int, 4
}
Full example here.
In order to throw an exception if the type is not supported, simply add a lambda that throws at the end of the fold expression:
([&]{ if(c.GetDataType() == types ) { std::invoke(f, cast<types>(c), args...); return true; } return false; }() || ... || []() -> bool{ throw (std::runtime_error("Type not supported")); }());
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Extracting element with specific type from string with generic lambda

I am using c++. I have string which can contains element start with ^ and end with $. This element can be int or string.
Example:
"....^15$asdasd"-> 15
"...^bbbb$ccc"->"bbbb"
I would like to write lambda function which would do this.
If I use template function the code would look like this:
template <typename T>
T getElem(string S)
{
T retElem;
// make calculations
// ....
return retElem;
}
but when I try using generic lambda I am reaching this situation :
auto getElem = [] () {
T retElem;
// make calculations
// ....
return retElem;
};
the problem is how to get type of retElem. Is there a way to use lambda in this case. I want to use generic lambda in function, where such such extraction is used. I want to to encapsulate this logic only in the function.
Generic lambdas have to have the argument of a (templated) type, you can't have generic lambda templatized on a non-argument. The easiest way to solve your problem is to provide a dummy argument of a given type. As in:
template<class T>
struct identity { using type = T; };
...
auto lam = [](auto the_type) {
using T = typename decltype(the_type)::type;
...
};
...
lam(identity<T>{});
...
Since it is C++14, you can use compiler type inference through decltype(auto):
int i = []() -> decltype(auto) {
return 1;
}();

Function wrapper that works for all kinds of functors without casting

I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]