Reputation: 13434
Suppose you have a function that takes a std::vector
of any type and processes it in some way:
template<typename T>
void foo(std::vector<T> &vec) {
// work with vec
}
Since C++14
, we are able to achieve the same thing with lambdas. In this case, we call them generic lambdas, since we introduce a template-like deduction to them:
auto foo_lambda = [](std::vector<auto> &vec) {
// work with vec
};
But our options seem quite limited to me. Suppose that I not only have to introduce a type deduction, but I also need to introduce template values. For example, let's change std::vector
to std::array
:
template<typename T, std::size_t size>
void foo(std::array<T, size> &arr) {
// work with arr
}
When dealing with template functions, we are able to introduce a template value, which can be used to match argument's needs. Neat.
I wanted to achieve the same functionality with generic lambdas, but I was unable to do so.
Is there a way to introduce a similar, deduced value to a lambda expression so any std::array
s can be used with said lambda, similarily to the second version of the foo()
function above?
EDIT: As stated in the comments by Evg, my vector<auto>
syntax is non-standard GCC extension. For details see this answer referring to this document.
Upvotes: 5
Views: 714
Reputation: 66240
Is there a way to introduce a similar, deduced value to a lambda expression so any std::arrays can be used with said lambda, similarily to the second version of the foo() function above?
Yes. But, unfortunately, starting (presumably) from C++20
auto foo_lambda = []<typename T, std::size_t S>(std::array<T, S> & arr)
{ /* ... */ };
In C++14/C++17 you can use decltype()
to extract what you need.
In the std::array
case, something as
auto foo_lambda = [](auto & arr)
{
using T = typename std::remove_reference_t<decltype(arr)>::value_type;
std::size_t S = arr.size();
// ...
};
With other types, you can develop custom type traits to extract the needed elements starting from decltype(arr)
.
Upvotes: 4
Reputation: 275750
Your vector<auto>
syntax is wrong.
You can tear apart the type of the auto
parameter in the return type/body of the lambda using helper functions and trait classes.
\http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0428r1.pdf is a proposal to add []<template T>( std::vector<T>& ){}
to the lamguage. Something like it should be in c++20.
I've done double lambdas before:
template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag{};
template<class Tag>using type_t=typename Tag::type;
auto f = [](auto tag_T){ return []( std::vector<type_t<decltype(tag_T)>> const& v){ /* code */ }; };
and use like:
f(tag<int>)( std::vector<int>{} );
where we use values as template type parameters.
Upvotes: 0
Reputation: 37599
You can use some dedicated type trait:
#include <type_traits>
#include <utility>
#include <array>
template<typename x_Whatever> struct
is_array: ::std::false_type {};
template<typename x_Item, ::std::size_t x_items_count> struct
is_array<::std::array<x_Item, x_items_count>>: ::std::true_type {};
int main()
{
auto Do_SomethingWithArray
{
[](auto & should_be_array)
{
static_assert
(
is_array
<
::std::remove_reference_t<decltype(should_be_array)>
>::value
);
}
};
::std::array<int, 3> a{};
Do_SomethingWithArray(a); // Ok
int x{};
Do_SomethingWithArray(x); // error
}
Upvotes: 5