Lambda takes iterator as parameters - c++

How to create a lambda function that accepts iterators for vector,list,array?
Something like:
auto do_somthing=[](iterator beg,iterator end){
//code here
}

If you use C++14, generalized lambdas will solve your problem nicely.
auto do_something = [](auto begin, auto end) {
// code here
};
int x[]{ 1, 2, 3, 4 };
do_something(std::begin(x), std::end(x));
std::set<int> s{3, 4, 12, 55, 98 };
do_something(std::begin(s), std::end(s));

#rollbear answered this for C++14, using a generic lambda. In C++11, you can hand-code such a "generic lambda:"
struct GenericLambda
{
template <class It>
void operator() (It beg, It end) { /*:::*/ }
} do_something;

If you're limited to c++11, and you need the generic lambda because you're in a templated function where the container is a template argument, then you can get the iterator type like this:
template<class T>
void foo()
{
using iterator = typename T::iterator;
auto lambda = [](iterator beg,iterator end){}
}

Related

How to provide the function signature for a function taking iterators of stl containers?

I want to write a function my_func that can be called as so, but does not care that v is a std::vector, it could be any STL container. A bit like std::for_each:
std::vector<std::string> v = {...};
my_func(v.begin(), v.end());
But I cannot figure out the function signature.
void my_func(??? i1, ??? i2)
{
std::for_each(i1, i2, ...); // dumb example implementation
}
I am not great at template programming so even looking at the function declaration for std::for_each is not helping me.
Is there an easy implementation or is this fundamentally going to get messy with template vars?
It depends on how generic you want the function to be. If the iterator types have to match, then
template <typename T>
void my_func(T i1, T i2)
{
std::for_each(i1,i2,...); //dumb example implementation
}
is all you need. If you want them to be able to be different, then you just need another template parameter like
template <typename T, typename U>
void my_func(T i1, U i2)
{
std::for_each(i1,i2,...); //dumb example implementation
}
Finally, if you don't like dealing with templates you can use a lambda instead and let the compiler take care of this for you. That would give you
auto my_func = [](auto i1, auto i2)
{
std::for_each(i1,i2,...); //dumb example implementation
};
You could write a templated function
template<typename Iterator>
void my_func(Iterator startIter, const Iterator endIter)
{
std::for_each(startIter, endIter, /* lambda */);
}
In case of wondering, how to pass the third parameter of the std::for_each, you could provide one more template parameter
const auto defaultCallable = [](auto element){ }; // does nothing
template<typename Iterator, typename Callable = decltype(defaultCallable)>
void my_func(Iterator startIter, const Iterator endIter, Callable func = {})
{
std::for_each(startIter, endIter, func);
}
The syntax is not too obscure! The following way uses the range for at the point of use:
template <template<typename...> class Iterable, typename T>
void foo(
const Iterable<T>& y // the container
){
for (auto&& e : y){
// e is the 'thingy' in the container.
}
}
and you can pass any iterable container of arbitrary type to foo.

C++ Template Function to Iterate Over any Collection Member Field

I am attempting to write a template function that iterates over a user-specified field within some collection of structs. For example, I want to write the following C++:
struct Example {
int a;
bool b;
};
template<std::function<Field& (Class)> GetField, typename Field, typename Class>
void myFunc(std::iterator<Class> begin, size_t const length) {
cout << length << endl;
for (size_t i{ 0 }; i < length; ++begin, ++i) {
Field const &field{ GetField(*begin) };
// Forward field to some other template function
anotherTemplateFunction<Field>(field);
}
}
void main() {
Example exArray[]{ {5, true}, {8, false} };
std::list<Example> exList{ exArray, exArray + _countof(exArray) }
// Examples of how I would like to call myFunc...
myFunc<Example::a>(exArray, _countof(exArray));
myFunc<Example::b>(exList.begin(), exList.size());
}
The above doesn't work, but hopefully the intent is clear. How can I write the myFunc template method to accomplish generic iteration over some field of each iterated item? Alternatively, if there is some way (in Boost or the Standard Library) to directly create an iterator over exArray[i].a, that would also be acceptable.
What I usually use is something like:
void main() {
std::array<Example, 2> exArray{ {5, true}, {8, false} };
std::list<Example> exList{ exArray.begin(), exArray.end() };
auto access_a = [](Example& e)->int&{ return e.a;};
auto access_b = [](Example& e)->bool&{ return e.b;};
myFunc(exArray.begin(), exArray.end(), access_a);
myFunc(exList.begin(), exList.end(), access_b);
}
template<class ForwardIt, class Accessor>
void myFunc(ForwardIt begin,ForwardIt end, Accessor accessor) {
cout << end - begin << endl;
for (auto it = begin; it != end; it++) {
// Forward field to some other template function
anotherTemplateFunction(accessor(*it));
}
}
Please notice how I used std::array instead of a raw c style array.
If you have access to a c++11 compiler, std::array (or std::vector) should always be preferred over raw c arrays. ES.27
In order to need less boilerplate code, consider using some serialization libraries which solve this "iterating over class fields" problem, for example boost serialization or magic get.
It's simple if you know the pointer to member syntax and the likes. Unfortunately is so rarely used, is kind of an esoteric feature of the language:
template <class T> void foo(T);
template <auto Field, class It>
auto myFunc(It begin, It end)
{
for (; begin != end; ++begin)
{
foo((*begin).*Field);
}
}
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<&Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<&Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
For the template <auto Field you need C++17.
For C++11 the syntax is more verbose:
template <class T, class F, F T::* Field, class It>
void myFunc(It begin, It end)
{ /* same */ }
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<Example, int, &Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<Example, bool, &Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
A little bit OT to your question, but I don't understand why you complicate yourself with that initialization of std::list. In C++ your first container of choice should be std::vector.
Also there is no std::iterator

Receive iterators as arguments and know class

I need to create a method that receives iterators as arguments and return a templated collection of the same type.
I created a minimal example the demonstrates my need:
#include <list>
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int _i) : i(_i) {}
operator int() {
return i;
}
};
class B {
int i;
public:
B(int _i) : i(_i) {}
operator int() {
return i;
}
};
template <class T>
list<T> method(typename list<T>::iterator begin, typename list<T>::iterator end) {
list<T> res; // I need the template class here
for (; begin != end; begin++) {
cout << *begin; // Whatever...
}
return res;
}
int main() {
list<A> listA = {1, 2, 3};
list<B> listB = {4, 5, 6};
auto res1 = method(listA.begin(), listA.end()); // Cannot change
auto res2 = method(listB.begin(), listB.end()); // Cannot change
}
This is not a working example, but I am looking for a way to make this work.
The important part is the method and it's arguments, and that it will return a templated class with T. So I can change the method as much as i want but the auto res1 = method(listA.begin(), listA.end()); should stay the same. (not my code)
How can I do something like this?
In this particular case (if you know that it's std::list) you can get value_type from iterator itself:
template <class T>
auto method(T begin, T end) {
list<typename T::value_type> res; // I need the template class here
for (; begin != end; begin++) {
cout << *begin; // Whatever...
}
return res;
}
value_type = U only for std::list<U>
typename list<T>::iterator is a non-deduced context. You need to either pass the container itself or specify it as an explicit template argument.
Iterators designate a sequence; they do not have to be associated with a "collection". For example, you can create an iterator that reads input from the console.
If you want to restrict a function to only work with containers, then write it that way:
template <class T>
T f(const T& container) {
// whatever; code that uses begin() and end()?
}
This isn't possible. You can have iterators that don't correspond to any container. The function that calls method should create an empty list and pass a back_inserter to the list as the third argument to method. Use std:copy as an example of what your method should look like.

Template type could not be deduced

I got a (simplified) function Foo
template<typename It, typename T>
void Foo(It begin, It end, T&& CallBar)
{
CallBar(begin, end);
}
And another simplified function Bar
template<typename It>
It Bar(It begin, It end)
{
return begin;
}
When I call both functions in the following way
std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
Foo(v.begin(), v.end(), Bar);
I get the error
'declaration' : could not deduce template argument for 'identifier'
What else do I have to specify to make it compile?
The issue here is that since Bar is a function template, it does not know which Bar you want. You have to tell it what version of Bar to use. One way to do that is by specifying the template type. You can do that like:
Foo(v.begin(), v.end(), Bar<decltype(v.begin())>);
If you would like to not have to specify the template type, which to be honest, is a little brittle then we can wrap the call to Bar in a lambda. This will allow the compiler to do all of the type deduction for us which is a lot easier to maintain. For example if you change the iterator type nothing you neede to be changed unlie the previous solution. Thanks to 0x499602D2 that would be
Foo(v.begin(),v.end(),[](auto b,auto e){return Bar(b,e);})
What else do I have to specify to make it compile?
By example
template<typename It>
void Foo(It begin, It end, It(* CallBar)(It, It))
{
CallBar(begin, end);
}
You can use template templates to help solve this. As far as I know, it requires you to wrap your Bar function in a functor. By placing the functor template parameter first, you can specify it and let the iterator type be deduced.
#include <vector>
// T is a type that takes a 'class' template argument
template<template<class> class T, class It>
void Foo(It begin, It end)
{
T<It>()(begin, end);
}
template<typename It>
struct Bar
{
It operator()(It begin, It end)
{
return begin;
}
};
int main()
{
std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
Foo<Bar>(v.begin(), v.end());
return 0;
}

In C++11 is there a way to not require template arguments when calling a function that takes any callable as an argument, including bound methods?

In order to broaden my understanding of C++11, I'm experimenting with writing functional helpers and seeing if I can make calling them less verbose. Consider the following code:
#include <list>
int timesTwo(int x) { return x*2; }
int timesX(int x, int y) { return x*y; }
class Foo {
public:
Foo(int a) : value(a) {};
int fooTimesTwo() const { return value*2; };
int value;
};
template <class T, class U>
std::list<U> myMap(const std::list<T> &list, const std::function<U(const T &)> &func)
{
std::list<U> result;
for(typename std::list<T>::const_iterator it = list.begin(); it != list.end(); ++it) {
result.push_back(func(*it));
}
return result;
}
int main()
{
std::list<int> numbers = {1,2,3,4,5};
std::list<int> numbers2 = myMap<int,int>(numbers, [] (int x) { return x*2; });
std::list<int> numbers3 = myMap<int,int>(numbers, &timesTwo);
std::list<int> numbers4 = myMap<int,int>(numbers, std::bind(timesX, 2, std::placeholders::_1));
std::list<Foo> fooList = {Foo(1), Foo(2), Foo(3), Foo(4)};
std::list<int> numbers5 = myMap<Foo,int>(fooList, &Foo::fooTimesTwo);
return 0;
}
Is there anyway to rewrite myMap so that
all four of the calls to it in my code example do not require any template arguments, and...
there's only one general implementation, and I don't have to manually write an overloaded version for each combination of types I want to call it with?
I've tried changing the second argument of myMap to be a third templated type instead of std::function, but it fails because a) the second templated type U can't be inferred, and b) even if it could, the fourth call to myMap will cause an error on line 20 due to &Foo::fooTimesTwo not being a function or function pointer.
I'm willing to consider all of the various features of C++11 to do this, and I don't particularly care if it makes the declaration or definition of myMap obtuse or unreadable. I'm just wondering if it's possible and, if so, what sort of techniques and C++11 features can accomplish it.
You could attempt to implement std::invoke in C++11, but I think it would be really cumbersome.
It's fairly simple to make a function template for a generalized callable:
template <class T, class F>
auto myMap(const std::list<T> &list, F&& func)
-> std::list<typename std::decay<decltype(func(*list.begin()))>::type>
{
using U = typename std::decay<decltype(func(*list.begin()))>::type;
std::list<U> result;
for(typename std::list<T>::const_iterator it = list.begin(); it != list.end(); ++it) {
result.push_back(func(*it));
}
return result;
}
You get expression sfinae for free. Now there's only member function pointer to be taken care of:
template <class T, class F>
auto myMap(const std::list<T> &list, F&& func)
-> std::list<typename std::decay<decltype(((*list.begin()).*func)())>::type>
{
return myMap(list, [=](T const& t){ return (t.*func)(); });
}
Now you can call your functions as expected. demo
While at it, you could replace this ugly for loop with a ranged for:
for(auto const& elem : list) {
results.push_back(func(elem));
}
Or use an algorithm:
std::transform(list.begin(), list.end(), std::back_inserter(result), func);