Reputation: 183
I am trying to pass a lambda as parameter to a function that specifies if items should be included in a new vector.
At the moment I am using templates for the vector type (T) and the lambda expression (Func). But how can I make the function to take a lambda with T as parameter and bool as returning type?
This is my code actual:
#include <string>
#include <vector>
using namespace std;
// DTO with some members
struct DTO
{
int Id;
string Name;
string Note;
};
// Function to receive a new vector, containing the searched items
template<typename T, typename Func>
vector<T> Where(vector<T> input, Func lambda)
{
vector<T> v;
for (auto it = input.begin(); it != input.end(); ++it)
if (lambda(*it))
v.push_back(*it);
return v;
}
int main()
{
// Some test data
DTO dto1;
dto1.Id = 1;
dto1.Name = "Test";
dto1.Note = "asdasfa";
DTO dto2;
dto2.Id = 2;
dto2.Name = "Test";
dto2.Note = "asdasfa";
DTO dto3;
dto3.Id = 2;
dto3.Name = "Test2";
dto3.Note = "asdasfa";
DTO dto4;
dto4.Id = 2;
dto4.Name = "Test2";
dto4.Note = "asdasfa";
DTO dto5;
dto5.Id = 2;
dto5.Name = "Test2";
dto5.Note = "123";
vector<DTO> numbers2 =
{
dto1,dto2,dto3,dto4,dto5
};
// Get new vector with items where Name is Test and Note is asdasfa
auto test = Where(numbers2, [](DTO dto)
{
return dto.Name == "Test" &&
dto.Note == "asdasfa";
});
}
The goal is, to make it most comfortable, for the caller of the function.
Upvotes: 0
Views: 1123
Reputation: 25388
You can write your template like this:
template<typename T>
std::vector<T> Where(std::vector<T> input, std::function <bool (T)> f)
{
std::vector<T> v;
for (auto it = input.begin(); it != input.end(); ++it)
if (f(*it))
v.push_back(*it);
return v;
}
But then you must invoke it like this:
auto test = Where <DTO> (numbers2, [](DTO dto)
{
...
});
Edit: If you only ever want to pass a non-capturing lambda, it is slightly more efficient to define your template like this:
template<typename T>
std::vector<T> Where(std::vector<T> input, bool (* f) (T))
...
But you still need the 'extra machinery' at the call site that Lightness Races in Orbit refers to (I think template deduction fails because the number of template parameters no longer matches the number of parameters passed to Where
).
All-in-all, stick with your original code.
Upvotes: 1
Reputation: 385264
In general, we try to stray from making templates necessitate a certain signature.
We prefer to:
As it is, your function template looks good, and your usage looks good, and that's why everything works.
Sure, you could pass something that returned not-bool
that regardless worked in the if
statement. And you could pass something that took not-DTO
but worked anyway … but then so what? Just don't do those things. If it walks like a duck…
It's possible, with some machinery, to ensure that the callable takes specific arguments and returns a value of a specific type, but that would be complex and frankly not useful.
In short, your code is fine.
Upvotes: 2
Reputation: 395
Try changing the template signature of Where
to SFINAE out the Func
types you don't want:
template<typename T,
typename Func,
std::enable_if_t<std::is_same_v<bool, std::invoke_result_t<Func, T>>>* = nullptr>
vector<T> Where(vector<T> input, Func lambda)
Upvotes: 0