Binding a templated standard library function - c++

How do you do this? The alternative requires wrapping std::generate in a lambda or std::function and that's undesirable.
int main()
{
using array_int = std::array<int, 10>;
std::vector<array_int> vec(10);
std::for_each(vec.begin(), vec.end(),
std::bind(std::generate, std::placeholders::_1, []() { return 0; }));
return 0;
}
As noted the problem is std::generate takes an iterator pair. Let's pretend they're boost ranges instead:
boost::for_each(vec,
boost::bind(boost::generate, _1, []() { return 0; }));

I assume you're really going to pass something more useful to generate, because those arrays will already be filled with zeros, because vector value-initializes them.
Your bind expression will not pass the right number of arguments to generate, so specifying which specialization of generate you want is not the only problem. In order to state the specialization you need to know the type of the generator you want to pass, which is a lambda, so you need to hoist that out:
auto gen = [] { return 0; };
Then you need to say which generate you want:
std::generate<array_int::iterator, decltype(gen)>
Then you need to pass the right arguments to it:
std::bind(std::generate<array_int::iterator, decltype(gen)>,
std::bind(&array_int::begin, std::placeholders::_1),
std::bind(&array_int::end, std::placeholders::_1),
gen));
This still won't work, because array_int::begin and array_int::end are overloaded, so you need to cast them to array_int::iterator (array_int::*)() to get the non-const versions.
auto gen = [] { return 0; };
using memfunc = array_int::iterator (array_int::*)();;
std::bind(std::generate<array_int::iterator, decltype(gen)>,
std::bind((memfunc)&array_int::begin, std::placeholders::_1),
std::bind((memfunc)&array_int::end, std::placeholders::_1),
gen));
You can make that a little bit simpler with generate_n since you know the size, and maybe using data() instead of begin(), although you still need to cast it:
auto gen = [] { return 0; };
using memfunc = int* (array_int::*)();;
std::bind(std::generate_n<int*, int, decltype(gen)>,
std::bind((memfunc)&array_int::data, std::placeholders::_1),
10,
gen));
Or you could just use a lambda:
std::for_each(vec.begin(), vec.end(), [](array_int& a) {
std::generate(a.begin(), a.end(), []{ return 0; });
});
If you want to call boost::generate instead it's a bit easier as you don't need a nested bind expression, but you still need the type of the generator:
auto gen = [] { return 0; };
std::bind(boost::generate<array_int, decltype(gen)>,
std::placeholders::_1
gen);
Or with a lambda:
std::for_each(vec.begin(), vec.end(), [](array_int& a) {
boost::generate(a, []{ return 0; });
});

Related

Initialise a lambda function to be passed as a predicate to std::find_if in C++

I'm trying to initialise a lambda function and then passing as a predicate to std::find_if but receiving the following compiler error. "expression cannot be used as a function".
So how do you first initialise a lambda as a type auto variable and pass it in as a predicate function to an algorithm like std::find_if?
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<std::string> vec ={"this", "is", "a", "test", "to",
"see","if", "this", "works", "to", "this", "if"};
auto elimDups_lambda
{
[&vec]()
{
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
return vec;
}
};
for(auto& iter_vec:elimDups_lambda())
std::cout<<iter_vec<<std::endl;
auto lambda_size
{
[&vec](size_t x)
{
for(auto& iter_vec:vec)
{
if(iter_vec.size()==x)
return true;
else if(iter_vec >*vec.end())
return false;
}
}
};
size_t string_size =0;
std::cin>>string_size;
std::vector<std::string>::iterator find_word =
std::find_if(vec.begin(), vec.end(), lambda_size(string_size));
std::cout<<*find_word<<std::endl;
return 0;
}
Thank you.
In order to define a variable holding a lambda, you can use syntax similar to this:
auto lambda_var =
[&vec]()
{
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
return vec;
};
To use it when calling std::find_if, pass lambda_var (or the name of the variable holding the lambda that you need), as a 3rd parameter to std::find_if
in your code elimDups_lambda and lambda_size are not properly defined to be variables holding lambdas (if this is indeed what you wanted to achieve).
With the expression
lambda_size(string_size)
you call the lambda function, and then the returned bool result will be used as the predicate for std::find_if.
This will of course not work very well.
You can solve this in two ways:
Capture string_size in the lambda; Or
Make the lambda return another lambda for the size check:
auto lambda_size = [&vec](size_t size)
{
return [size](std::string const& word)
{
return word.length() == size;
}
}
Also note how I have changed the logic in the lambda for the comparisons. Your comparison could mean that you dereference the end() iterator for the vector, which isn't allowed. And also that there's a path where the lambda doesn't actually return anything.
Both those problems inside the lambda would lead to undefined behavior.

Calling a function with several arguments for every element in a collection

I've got a collection, for example, std::vector<MyClass> elements; and want to run a function for every element.
It's simple and transparent when the function has no arguments: std::for_each(elements.begin(), elements.end(), std::mem_fun(&MyClass::MyFunction));
The code starts looking ugly when the function has 1 argument and I need to use std::bind_2nd.
Is there a way (perhaps, using lambdas) to write a function call with several arguments?
Your code
std::for_each(v.begin(), v.end(), std::mem_fun(&MyClass::MyFunction));
is equivalent to
std::for_each(v.begin(), v.end(), [](auto& obj) { obj.MyFunction(); });
Now that the invocation of MyFunction is done in your code, you can pass other parameters to it as needed:
std::string arg1 = "hello";
int arg2 = 123;
std::for_each(v.begin(), v.end(), [&](auto& obj) { obj.MyFunction(arg1, arg2); });
Demo.
for_each works but as you said it might look less readable. I prefer the range-based for syntax a lot:
for(auto& element : elements)
element.foo( … );

Passing inferred type into std::find_if lambda function

I have the following code. I'm trying to eliminate the need for explicitly passing the localization_data_t::language_t type into the lambda argument.
auto language_itr = std::find_if(languages.begin(), languages.end(), [&](const localization_data_t::language_t& language)
{
return language.code == language_code;
});
I assume there is a way to do this since the type of the objects to be iterated over can be derived by the compiler via the iterator's underlying type. However, I have found no such example in my travels.
Any help would be appreciated.
You can use decltype in C++11:
auto result = std::find_if(v.begin(), v.end(), [](const decltype(*v.begin())& t) { /* */ });
in C++1y you can just use auto.
auto result = std::find_if(v.begin(), v.end(), [](const auto& t) { /* */ });
There's also std::iterator_traits but it's more verbose.

How to make an array of Lambda expressions [duplicate]

I was trying to create a vector of lambda, but failed:
auto ignore = [&]() { return 10; }; //1
std::vector<decltype(ignore)> v; //2
v.push_back([&]() { return 100; }); //3
Up to line #2, it compiles fine. But the line#3 gives compilation error:
error: no matching function for call to 'std::vector<main()::<lambda()>>::push_back(main()::<lambda()>)'
I don't want a vector of function pointers or vector of function objects. However, vector of function objects which encapsulate real lambda expressions, would work for me. Is this possible?
Every lambda has a different type—even if they have the same signature. You must use a run-time encapsulating container such as std::function if you want to do something like that.
e.g.:
std::vector<std::function<int()>> functors;
functors.push_back([&] { return 100; });
functors.push_back([&] { return 10; });
All lambda expressions have a different type, even if they are identical character-by-character. You're pushing a lambda of a different type (because it's another expression) into the vector, and that obviously won't work.
One solution is to make a vector of std::function<int()> instead.
auto ignore = [&]() { return 10; };
std::vector<std::function<int()>> v;
v.push_back(ignore);
v.push_back([&]() { return 100; });
On another note, it's not a good idea to use [&] when you're not capturing anything.
While what others have said is relevant, it is still possible to declare and use a vector of lambda, although it's not very useful:
auto lambda = [] { return 10; };
std::vector<decltype(lambda)> vec;
vec.push_back(lambda);
So, you can store any number of lambdas in there, so long as it's a copy/move of lambda!
If your lambda is stateless, i.e., [](...){...}, C++11 allows it to degrade into a function pointer. In theory, a C++11 compliant compiler would be able to compile this:
auto ignore = []() { return 10; }; //1 note misssing & in []!
std::vector<int (*)()> v; //2
v.push_back([]() { return 100; }); //3
You could use a lambda generating function (updated with fix suggested by Nawaz):
#include <vector>
#include <iostream>
int main() {
auto lambda_gen = [] (int i) {return [i](int x){ return i*x;};} ;
using my_lambda = decltype(lambda_gen(1));
std::vector<my_lambda> vec;
for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i));
int i = 0;
for (auto& lambda : vec){
std::cout << lambda(i) << std::endl;
i++;
}
}
But I think you basically made your own class at this point. Otherwise if the lambdas have completely different caputres/args etc. you probably have to use a tuple.
Each lambda is a different type. You must use std::tuple instead of std::vector.

Why can't I create a vector of lambdas (of the same type) in C++11?

I was trying to create a vector of lambda, but failed:
auto ignore = [&]() { return 10; }; //1
std::vector<decltype(ignore)> v; //2
v.push_back([&]() { return 100; }); //3
Up to line #2, it compiles fine. But the line#3 gives compilation error:
error: no matching function for call to 'std::vector<main()::<lambda()>>::push_back(main()::<lambda()>)'
I don't want a vector of function pointers or vector of function objects. However, vector of function objects which encapsulate real lambda expressions, would work for me. Is this possible?
Every lambda has a different type—even if they have the same signature. You must use a run-time encapsulating container such as std::function if you want to do something like that.
e.g.:
std::vector<std::function<int()>> functors;
functors.push_back([&] { return 100; });
functors.push_back([&] { return 10; });
All lambda expressions have a different type, even if they are identical character-by-character. You're pushing a lambda of a different type (because it's another expression) into the vector, and that obviously won't work.
One solution is to make a vector of std::function<int()> instead.
auto ignore = [&]() { return 10; };
std::vector<std::function<int()>> v;
v.push_back(ignore);
v.push_back([&]() { return 100; });
On another note, it's not a good idea to use [&] when you're not capturing anything.
While what others have said is relevant, it is still possible to declare and use a vector of lambda, although it's not very useful:
auto lambda = [] { return 10; };
std::vector<decltype(lambda)> vec;
vec.push_back(lambda);
So, you can store any number of lambdas in there, so long as it's a copy/move of lambda!
If your lambda is stateless, i.e., [](...){...}, C++11 allows it to degrade into a function pointer. In theory, a C++11 compliant compiler would be able to compile this:
auto ignore = []() { return 10; }; //1 note misssing & in []!
std::vector<int (*)()> v; //2
v.push_back([]() { return 100; }); //3
You could use a lambda generating function (updated with fix suggested by Nawaz):
#include <vector>
#include <iostream>
int main() {
auto lambda_gen = [] (int i) {return [i](int x){ return i*x;};} ;
using my_lambda = decltype(lambda_gen(1));
std::vector<my_lambda> vec;
for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i));
int i = 0;
for (auto& lambda : vec){
std::cout << lambda(i) << std::endl;
i++;
}
}
But I think you basically made your own class at this point. Otherwise if the lambdas have completely different caputres/args etc. you probably have to use a tuple.
Each lambda is a different type. You must use std::tuple instead of std::vector.