Juliean said:
for (std::vector::iterator itr = vector.begin(); itr != vector.end(); ++itr) { function(*itr); }
But that's really a bad example, because stl container iterators are much more cumbersome than the same code in C:
for (int *ptr = array; ptr < array+size; ptr++)
{
function (*ptr);
}
Not so much more code than your modern version.
A pattern that has affected my coding the most form adopting modern features is lambdas combined with templates to replace cumbersome callbacks:
#if 0 // slow:
void BlockParticlesAdjacencyIterator (const int block,
const float interactRadius, const float delta_x, const float cellMaxRad,
std::function<bool (const int pI)> OpenOuterLoop,
std::function<void (const int aBegin, const int aEnd)> IterateInnerLoop,
std::function<void (const int pI)> CloseOuterLoop
)
#else // fast:
template <typename L0, typename L1, typename L2>
void BlockParticlesAdjacencyIterator (const int block,
const float interactRadius, const float delta_x,
L0 OpenOuterLoop, L1 IterateInnerLoop, L2 CloseOuterLoop)
#endif
{
// code here does all the things needed to iterate adjacent particles within given radius
// that's complicated - needs to traverse tree to fuind adjacent blocks, cache results to minimaze traversals, iterate particles per sub cell
// so i really only want to rite this iteration code once
}
some example using this:
auto OpenOuterLoop = [&](const int pI)
{
// here we may do setup stuff, like initializing variables to zero where we accumulate stuff from neighbors to a current particle
};
auto IterateInnerLoop = [&](const int aBegin, const int aEnd)
{
for (int apI = aBegin; apI < aEnd; apI++) //if (apI != pI) // iterate adjacent particles of a given block
{
Particle &ap = particles[apI];
// do some interaction of particles, accumulate, etc...
}
};
auto CloseOuterLoop = [&](const int pI)
{
// her we may write results to memory, or do other closing stuff on the current particle
};
BlockParticlesAdjacencyIterator (block, interactRadius, delta_x,
OpenOuterLoop, IterateInnerLoop, CloseOuterLoop);
Before modern C++, i had to write iterator objects to do this. This was often harder, e.g. if we traverse a tree, maintaining all state in such object and modelling all potential interactions with user code was MUCH more work than writing tree traversal in place.
Now i can do it the other way around. No more iterator object, but writing little lambdas to handle interactions and decisions. I really like this and use it often.
If there were no lambdas, i could create small structs or classes within my user function. But that's only possible since C++11 too, so we can just use lambdas.
The traditional alternatives would cause many callbacks and objects at global scope, cluttering code base, although we need the stuff inside of just one function.
That's so far where modern C++ really shines to me, but i still lag behind and don't know about most features you guys mention.
The interesting detail is performance. You see on the #ifdef i had tried std::function before, which works and is equally convenient.
But the cost was too big. Using templates, results with Clang where the same performance as with writing inline iteration code. With MSVC this still has some extra cost like 5% in my example of fluid simulation.
If you have some concerns, please let me know ; )
Templates will cause a larger executable, but so would copy pasting iteration code to many functions. So i'm very happy with this pattern.