python-style function list input for c++ - c++

I want to have an input to a function similar to python so that then I can loop over it in inside the function. But I am not sure how I should define the input.
func(["a","b","c"])
so that it can also be called
func(["a","b","c", "d"])
is there actually such style of input in c++?
I'd be glad if someone also suggested a way of looping over it since my c++ experience is quite basic.
-------edit,
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.

Yes, you can use std::initializer_list to do that:
#include <initializer_list>
template<class T>
void func(std::initializer_list<T> il) {
for (auto x : il);
}
int main() {
func({"a","b","c"});
func({"a","b","c", "d"});
}
will be glad if this "[]" style of brackets are possible instead of
"{}" similar to python and with minimal code.
Unfortunately, the multidimensional subscript operator only works in C++23, see p2128 for more details.

You can use a std::initilializer_list:
#include <iostream>
#include <initializer_list>
void foo(std::initializer_list<std::string> l){
for (const auto& s : l) std::cout << s << " ";
}
int main() {
foo({"a","b","c"});
}
I think python does not distinguish between character and string literals, but C++ does. "a" is a string literal, while 'a' is a character literal. If you actually wanted characters you can use a std::initializer_list<char>. You can also consider to simply pass a std::string to the function (foo("abc")).
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Better get used to different languages being different. Trying to make code in one language look like a different language usually does not pay off, because not only in details python and C++ are very different.

The other answers will work but I think your looking for std::vector, which is a array that can dynamically grow and shrink. It is basically the c++ equivalent to a python list (except you can only store on data type in it).
#include <iostream>
#include <vector>
void foo (std::vector<std::string> vec)
{
// normal for loop
for (int i = 0; i < vec.size (); i++)
{
std::cout << vec[i] << std::endl; // do something
}
std::cout << "#########" << std::endl;
// range based for loop
for (auto val : vec)
{
std::cout << val << std::endl;
}
std::cout << "#########" << std::endl;
}
int main ()
{
foo ({'a', 'b', 'c'});
foo ({'a', 'b', 'c', 'd'});
}
replace std::string with the data type that you need.
live example

I would recommend you to use std::initializer_list for that purpose.
The function may be defined as follows:
void func(std::initializer_list<std::string> il)
{
for(const std::string & s : il)
{
// ...
}
}
And you may use it the following way:
int main()
{
func({"a", "b", "c"});
return 0;
}
will be glad if this "[]" style of brackets are possible instead of "{}" similar to python and with minimal code.
Python and C++ are not the same languages and symbols, keywords, etc... have their own meaning. In Python, [] means a list, but in C++ it is the subscript operator (supposed to be called for a given object), which is a completely different thing.

Related

Accommodation for dynamic array

From this discussion, I have the following code to check if an element exists in an array:
#include <iostream>
#include <vector>
template <typename T, std::size_t N>
bool IsIn(T value, const T(&values)[N])
{
for (const T& array_value : values)
{
if (value == array_value) return true;
}
return false;
}
int main() {
int arr1[] = { 10, 20, 30 };
bool ee1 = IsIn(10, arr1);
std::cout << "ee1 = " << (ee1?"true":"false") << "\n";
return 0;
}
I believe this code is good for array of fixed size (at compile time) only. If the array is dynamically created (the number of elements is not known at compile time), is there any way I can modify the code to accommodate it?
PS: I am aware of vector. However, I am just curious if there is any way to avoid it.
Don't use C-style arrays unless you absolutely need to. Use std::array instead. For dynamic arrays, use std::vector.
You can then use iterators to make your function generic. However, this function already exists, it's called std::find. You can try to implement your own, for learning purposes, or look up an example implementation here: cppreference | find
#include <algorithm>
#include <array>
#include <iostream>
#include <string>
#include <vector>
int main(){
std::array<int, 3> static_array{1, 2, 3};
std::vector<int> dynamic_array{3, 4, 5};
std::string str = "Hello World";
std::array<int, 3>::iterator stat_found;
if( (stat_found = std::find(static_array.begin(), static_array.end(), 3)) != static_array.end() ){
std::cout << "Found 3 in static_array at pos: " << stat_found - static_array.begin() << "\n";
}
std::vector<int>::iterator dyn_found;
if( (dyn_found = std::find(dynamic_array.begin(), dynamic_array.end(), 3)) != dynamic_array.end() ){
std::cout << "Found 3 in dynamic_array at pos: " << dyn_found - dynamic_array.begin() << "\n";
}
std::string::iterator str_found;
if( (str_found = std::find(str.begin(), str.end(), 'W')) != str.end() ){
std::cout << "Found W in string at pos: " << str_found - str.begin() << "\n";
}
}
Without changing the body of your method, you can accommodate practically any collection type by abstracting over the collection type as well, i.e.
template <typename T, typename Collection>
bool IsIn(T value, const Collection &values)
{
/* ... */
}
However, as inifnitezero noted, the standard way of doing this is actually with iterators, and many implementations already exist in the standard library for this.
For a dynamic array you have to pass in the size in some form or another.
template <typename T>
bool IsIn(T value, const T *arr, std::size_t size) { ... }
You already know about std::vector, which knows it's own size, so I will skip that. That is the way to handle dynamic arrays. But not the only way to pass them to a function.
You can use std::span, which can be used for fixed sized arrays, std::array, std::vector and any container with random access iterator (sequential iterator? not sure). It's probably the most flexible thing to use.
You can also use begin and end const iterators. But that involves a lot of typing unless you already have 2 iterators when you want to call it.
Personally I think std::span covers all the bases. You can even make a span from iterators.

Equivalent of Enum for Strings

I studied enums which expects only integer inputs and returns corresponding value to it.I want to achieve same thing but I only have strings as a input. I want to make following work -
enum Types {
"Absolute", //"abs"
"PURE", //"PRE"
"MIXED" //"MXD"
}
and probable statment could be -
string sTpes = Types("abs"); //this should return "Absolute"
or
string sTpes = Types("MXD"); //this should return "MIXED"
If not using enums, please suggest me possible ways to achieve this.
Thanks.
There are no "string-enums", but to map from one value to another, you can use std::map, which is a standard template shipped with C++ platforms:
#include <map>
#include <string>
int main() {
using std::map; using std::string;
map<string, string> ss;
ss["abs"] = "Absolute";
const string foo = ss["abs"];
std::cout << ss["abs"] << ", or " << foo << std::endl;
}
In C++0x, if you want "safe" access that throws an exception if the key-type wasn't found, use map::at (actually, afair, the lack of map::at was just an oversight in the current standard):
std::cout << ss.at("weird keY");
or check if it exists:
if (ss.find("weird keY")==ss.end())
std::cout << "key not found\n";
if you are talking about c++/cli you could use this
Hashtable^ openWith = gcnew Hashtable();
// Add some elements to the hash table. There are no
// duplicate keys, but some of the values are duplicates.
openWith->Add("txt", "notepad.exe");
openWith->Add("bmp", "paint.exe");
openWith->Add("dib", "paint.exe");
openWith->Add("rtf", "wordpad.exe");
from http://msdn.microsoft.com/fr-fr/library/system.collections.hashtable.aspx#Y4406
else use map from stdlib.
I think you can also use CMAP from MFC, there is a good article about it here : http://www.codeproject.com/KB/architecture/cmap_howto.aspx
An enum has an integral value. Personally I simply suggest two conversion functions:
enum -> string
string -> enum
The first can be implemented with a simple array, the second require a binary search in a sorted list.
you could use a string array (of size 2) from string.h i think (either that or just string; one is for C and other is for cpp). first string is "abs" second is "absolute".
for example:
#include <string>
...
string abs[2]; //or a better name that's more relevant to you
abs[0] = "abs";
abs[1] = "absolute";
...
//pass it into the function
cout << abs[1] << endl;
...

C++ range/xrange equivalent in STL or boost?

Is there C++ equivalent for python Xrange generator in either STL or boost?
xrange basically generates incremented number with each call to ++ operator.
the constructor is like this:
xrange(first, last, increment)
was hoping to do something like this using boost for each:
foreach(int i, xrange(N))
I. am aware of the for loop. in my opinion they are too much boilerplate.
Thanks
my reasons:
my main reason for wanting to do so is because i use speech to text software, and programming loop usual way is difficult, even if using code completion. It is much more efficient to have pronounceable constructs.
many loops start with zero and increment by one, which is default for range. I find python construct more intuitive
for(int i = 0; i < N; ++i)
foreach(int i, range(N))
functions which need to take range as argument:
Function(int start, int and, int inc);
function(xrange r);
I understand differences between languages, however if a particular construct in python is very useful for me and can be implemented efficiently in C++, I do not see a reason not to use it. For each construct is foreign to C++ as well however people use it.
I put my implementation at the bottom of the page as well the example usage.
in my domain i work with multidimensional arrays, often rank 4 tensor. so I would often end up with 4 nested loops with different ranges/increments to compute normalization, indexes, etc. those are not necessarily performance loops, and I am more concerned with correctness readability and ability to modify.
for example
int function(int ifirst, int ilast, int jfirst, int jlast, ...);
versus
int function(range irange, range jrange, ...);
In the above, if different strids are needed, you have to pass more variables, modify loops, etc. eventually you end up with a mass of integers/nearly identical loops.
foreach and range solve my problem exactly. familiarity to average C++ programmer is not high on my list of concerns - problem domain is a rather obscure, there is a lot of meta-programming, SSE intrinsic, generated code.
Boost irange should really be the answer (ThxPaul Brannan)
I'm adding my answer to provide a compelling example of very valid use-cases that are not served well by manual looping:
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/irange.hpp>
using namespace boost::adaptors;
static int mod7(int v)
{ return v % 7; }
int main()
{
std::vector<int> v;
boost::copy(
boost::irange(1,100) | transformed(mod7),
std::back_inserter(v));
boost::sort(v);
boost::copy(
v | reversed | uniqued,
std::ostream_iterator<int>(std::cout, ", "));
}
Output: 6, 5, 4, 3, 2, 1, 0,
Note how this resembles generators/comprehensions (functional languages) and enumerables (C#)
Update I just thought I'd mention the following (highly inflexible) idiom that C++11 allows:
for (int x : {1,2,3,4,5,6,7})
std::cout << x << std::endl;
of course you could marry it with irange:
for (int x : boost::irange(1,8))
std::cout << x << std::endl;
Boost has counting_iterator as far as I know, which seems to allow only incrementing in steps of 1. For full xrange functionality you might need to implement a similar iterator yourself.
All in all it could look like this (edit: added an iterator for the third overload of xrange, to play around with boost's iterator facade):
#include <iostream>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/foreach.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <cassert>
template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T to)
{
//these assertions are somewhat problematic:
//might produce warnings, if T is unsigned
assert(T() <= to);
return boost::make_iterator_range(boost::counting_iterator<T>(0), boost::counting_iterator<T>(to));
}
template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T from, T to)
{
assert(from <= to);
return boost::make_iterator_range(boost::counting_iterator<T>(from), boost::counting_iterator<T>(to));
}
//iterator that can do increments in steps (positive and negative)
template <class T>
class xrange_iterator:
public boost::iterator_facade<xrange_iterator<T>, const T, std::forward_iterator_tag>
{
T value, incr;
public:
xrange_iterator(T value, T incr = T()): value(value), incr(incr) {}
private:
friend class boost::iterator_core_access;
void increment() { value += incr; }
bool equal(const xrange_iterator& other) const
{
//this is probably somewhat problematic, assuming that the "end iterator"
//is always the right-hand value?
return (incr >= 0 && value >= other.value) || (incr < 0 && value <= other.value);
}
const T& dereference() const { return value; }
};
template <class T>
boost::iterator_range<xrange_iterator<T> > xrange(T from, T to, T increment)
{
assert((increment >= T() && from <= to) || (increment < T() && from >= to));
return boost::make_iterator_range(xrange_iterator<T>(from, increment), xrange_iterator<T>(to));
}
int main()
{
BOOST_FOREACH(int i, xrange(10)) {
std::cout << i << ' ';
}
BOOST_FOREACH(int i, xrange(10, 20)) {
std::cout << i << ' ';
}
std::cout << '\n';
BOOST_FOREACH(int i, xrange(0, 46, 5)) {
std::cout << i << ' ';
}
BOOST_FOREACH(int i, xrange(10, 0, -1)) {
std::cout << i << ' ';
}
}
As others are saying, I don't see this buying you much over a normal for loop.
std::iota (not yet standardized) is kinda like range. Doesn't make things any shorter or clearer than an explicit for loop, though.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main() {
std::vector<int> nums(5);
std::iota(nums.begin(), nums.end(), 1);
std::copy(nums.begin(), nums.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
Compile with g++ -std=c++0x; this prints "1 2 3 4 5 \n".
well, here is what i wrote, since there does not seem to be one.
the generator does not use any internal storage besides single integer.
range object can be passed around and used in nested loops.
there is a small test case.
#include "iostream"
#include "foreach.hpp"
#include "boost/iterator/iterator_categories.hpp"
struct range {
struct iterator_type {
typedef int value_type;
typedef int difference_type;
typedef boost::single_pass_traversal_tag iterator_category;
typedef const value_type* pointer;
typedef const value_type & reference;
mutable value_type value;
const difference_type increment;
iterator_type(value_type value, difference_type increment = 0)
: value(value), increment(increment) {}
bool operator==(const iterator_type &rhs) const {
return value >= rhs.value;
}
value_type operator++() const { return value += increment; }
operator pointer() const { return &value; }
};
typedef iterator_type iterator;
typedef const iterator_type const_iterator;
int first_, last_, increment_;
range(int last) : first_(0), last_(last), increment_(1) {}
range(int first, int last, int increment = 1)
: first_(first), last_(last), increment_(increment) {}
iterator begin() const {return iterator(first_, increment_);}
iterator end() const {return iterator(last_);}
};
int test(const range & range0, const range & range1){
foreach(int i, range0) {
foreach(int j, range1) {
std::cout << i << " " << j << "\n";
}
}
}
int main() {
test(range(6), range(3, 10, 3));
}
my main reason for wanting to do so is because i use speech to text software, and programming loop usual way is difficult, even if using code completion. It is much more efficient to have pronounceable constructs.
That makes sense. But couldn't a simple macro solve this problem? #define for_i_to(N, body) for (int i = 0; i < N; ++i) { body }
or something similar. Or avoid the loop entirely and use the standard library algorithms. (std::for_each(range.begin(), rang.end(), myfunctor()) seems easier to pronounce)
many loops start with zero and increment by one, which is default for range. I find python construct more intuitive
You're wrong. The Python version is more intuitive to a Python programmer. And it may be more intuitive to a non-programmer. But you're writing C++ code. Your goal should be to make it intuitive to a C++ programmer. And C++ programmer know for-loops and they know the standard library algorithms. Stick to using those. (Or stick to writing Python)
functions which need to take range as argument:
Function(int start, int and, int inc);
function(xrange r);
Or the idiomatic C++ version:
template <typename iter_type>
void function(iter_type first, iter_type last);
In C++, ranges are represented by iterator pairs. Not integers.
If you're going to write code in a new language, respect the conventions of that language. Even if it means you have to adapt and change some habits.
If you're not willing to do that, stick with the language you know.
Trying to turn language X into language Y is always the wrong thing to do. It own't work, and it'll confuse the language X programmers who are going to maintain (or just read) your code.
Since I've started to use BOOST_FOREACH for all my iteration (probably a misguided idea, but that's another story), here's another use for aaa's range class:
std::vector<int> vec;
// ... fill the vector ...
BOOST_FOREACH(size_t idx, make_range(0, vec.size()))
{
// ... do some stuff ...
}
(yes, range should be templatized so I can use user-defined integral types with it)
And here's make_range():
template<typename T>
range<T> make_range(T const & start, T const & end)
{
return range<T>(start, end);
}
See also:
http://groups.google.com/group/boost-list/browse_thread/thread/3e11117be9639bd
and:
https://svn.boost.org/trac/boost/ticket/3469
which propose similar solutions.
And I've just found boost::integer_range; with the above example, the code would look like:
using namespace boost;
std::vector<int> vec;
// ... fill the vector ...
BOOST_FOREACH(size_t idx, make_integer_range(0, vec.size()))
{
// ... do some stuff ...
}
C++ 20's ranges header has iota_view which does this:
#include <ranges>
#include <vector>
#include <iostream>
int main()
{
for (int i : std::views::iota{1, 10})
std::cout << i << ' ';
std::cout << '\n';
for (int i : std::views::iota(1) | std::views::take(9))
std::cout << i << ' ';
}
Output:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
Since we don't really know what you actually want to use this for, I'm assuming your test case is representative. And then plain simple for loops are a whole lot simpler and more readable:
int main() {
for (int i = 0; i <= 6; ++i){
for (int j = 3; j <= 10; j += 3){
std::cout << i << " " << j << "\n";
}
}
}
A C++ programmer can walk in from the street and understand this function without having to look up complex classes elsewhere. And it's 5 lines instead of your 60. Of course if you have 400 loops exactly like these, then yes, you'd save some effort by using your range object. Or you could just wrap these two loops inside a helper function, and call that whenever you needed.
We don't really have enough information to say what's wrong with simple for loops, or what would be a suitable replacement. The loops here solve your problem with far less complexity and far fewer lines of code than your sample implementation. If this is a bad solution, tell us your requirements (as in what problem you need to solve, rather than "I want python-style loops in C++")
Keep it simple, make a stupid macro;
#define for_range(VARNAME, START, STOP, INCREMENT) \
for(int VARNAME = START, int STOP_ = STOP, INCREMENT_ = INCREMENT; VARNAME != STOP_; VARNAME += INCREMENT_)
and use as;
for_range(i, 10, 5, -1)
cout << i << endl;
You're trying to bring a python idiom into C++. That's unncessary. Use
for(int i=initVal;i<range;i+=increment)
{
/*loop body*/
}
to achieve this. In Python, the for(i in xrange(init, rng, increment)) form is necessary because Python doesn't provide a simple for loop, only a for-each type construct. So you can iterate only over a sequence or a generator. This is simply unnecessary and almost certainly bad practice in a language that provides a for(;;) syntax.
EDIT: As a completely non-recommended aside, the closest I can get to the for i xrange(first, last, inc) syntax in C++ is:
#include <cstdio>
using namespace std;
int xrange(unsigned int last, unsigned int first=0, unsigned int inc=1)
{
static int i = first;
return (i<last)?i+=inc:i=0;
}
int main()
{
while(int i=xrange(10, 0, 1))
printf("in loop at i=%d\n",i);
}
Not that while this loops the correct number of times, i varies from first+inc to last and NOT first to last-inc as in Python. Also, the function can only work reliably with unsigned values, as when i==0, the while loop will exit. Do not use this function. I only added this code here to demonstrate that something of the sort is indeed possible. There are also several other caveats and gotchas (the code won't really work for first!=0 on subsequent function calls, for example)

Abusing the comma operator

I'm looking for an easy way to build an array of strings at compile time. For a test, I put together a class named Strings that has the following members:
Strings();
Strings(const Strings& that);
Strings(const char* s1);
Strings& operator=(const char* s1);
Strings& operator,(const char* s2);
Using this, I can successfully compile code like this:
Strings s;
s="Hello","World!";
The s="Hello" part invokes the operator= which returns a Strings& and then the operator, get called for "World!".
What I can't get to work (in MSVC, haven't tried any other compilers yet) is
Strings s="Hello","World!";
I'd assume here that Strings s="Hello" would call the copy constructor and then everything would behave the same as the first example. But I get the error: error C2059: syntax error : 'string'
However, this works fine:
Strings s="Hello";
So I know that the copy constructor does at least work for one string. Any ideas? I'd really like to have the second method work just to make the code a little cleaner.
I think that the comma in your second example is not the comma operator but rather the grammar element for multiple variable declarations.
e.g., the same way that you can write:
int a=3, b=4
It seems to me that you are essentially writing:
Strings s="Hello", stringliteral
So the compiler expects the item after the comma to be the name of a variable, and instead it sees a string literal and announces an error. In other words, the constructor is applied to "Hello", but the comma afterwards is not the comma operator of Strings.
By the way, the constructor is not really a copy constructor. It creates a Strings object from a literal string parameter... The term copy constructor is typically applied to the same type.
I wouldn't recommend this kind of an API. You are going to continue discovering cases that don't work as expected, since comma is the operator with the lowest precedence. For example, this case won't work either:
if ("Hello","world" == otherStrings) { ... }
You may be able to get things working if you use brackets every time around the set of strings, like this:
Strings s=("Hello","World!");
And my example above would look like this:
if (("Hello","world") == otherStrings) { ... }
That can likely be made to work, but the shorthand syntax is probably not worth the tricky semantics that come with it.
Use boost::list_of.
It's possible to make this work, for a sufficiently loose definition of "work." Here's a working example I wrote in response to a similar question some years ago. It was fun as a challenge, but I wouldn't use it in real code:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
void f0(std::vector<int> const &v) {
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, "\t"));
std::cout << "\n";
}
template<class T>
class make_vector {
std::vector<T> data;
public:
make_vector(T const &val) {
data.push_back(val);
}
make_vector<T> &operator,(T const &t) {
data.push_back(t);
return *this;
}
operator std::vector<T>() { return data; }
};
template<class T>
make_vector<T> makeVect(T const &t) {
return make_vector<T>(t);
}
int main() {
f0((makeVect(1), 2, 3, 4, 5));
f0((makeVect(1), 2, 3));
return 0;
}
You could use an array of character pointers
Strings::Strings(const char* input[]);
const char* input[] = {
"string one",
"string two",
0};
Strings s(input);
and inside the constructor, iterate through the pointers until you hit the null.
If the only job of Strings is to store a list of strings, then boost::assign could do the job better with standard containers, I think :)
using namespace boost::assign;
vector<string> listOfThings;
listOfThings += "Hello", "World!";
If you c++0x, they have new inializer lists for this! I wish you could use those. For example:
std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" };

C++ STL - iterate through everything in a sequence

I have a sequence, e.g
std::vector< Foo > someVariable;
and I want a loop which iterates through everything in it.
I could do this:
for (int i=0;i<someVariable.size();i++) {
blah(someVariable[i].x,someVariable[i].y);
woop(someVariable[i].z);
}
or I could do this:
for (std::vector< Foo >::iterator i=someVariable.begin(); i!=someVariable.end(); i++) {
blah(i->x,i->y);
woop(i->z);
}
Both these seem to involve quite a bit of repetition / excessive typing. In an ideal language I'd like to be able to do something like this:
for (i in someVariable) {
blah(i->x,i->y);
woop(i->z);
}
It seems like iterating through everything in a sequence would be an incredibly common operation. Is there a way to do it in which the code isn't twice as long as it should have to be?
You could use for_each from the standard library. You could pass a functor or a function to it. The solution I like is BOOST_FOREACH, which is just like foreach in other languages. C+0x is gonna have one btw.
For example:
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
void print(int v)
{
std::cout << v << std::endl;
}
int main()
{
std::vector<int> array;
for(int i = 0; i < 100; ++i)
{
array.push_back(i);
}
std::for_each(array.begin(), array.end(), print); // using STL
foreach(int v, array) // using Boost
{
std::cout << v << std::endl;
}
}
Not counting BOOST_FOREACH which AraK already suggested, you have the following two options in C++ today:
void function(Foo& arg){
blah(arg.x, arg.y);
woop(arg.z);
}
std::for_each(someVariable.begin(), someVariable.end(), function);
struct functor {
void operator()(Foo& arg){
blah(arg.x, arg.y);
woop(arg.z);
}
};
std::for_each(someVariable.begin(), someVariable.end(), functor());
Both require you to specify the "body" of the loop elsewhere, either as a function or as a functor (a class which overloads operator()). That might be a good thing (if you need to do the same thing in multiple loops, you only have to define the function once), but it can be a bit tedious too. The function version may be a bit less efficient, because the compiler is generally unable to inline the function call. (A function pointer is passed as the third argument, and the compiler has to do some more detailed analysis to determine which function it points to)
The functor version is basically zero overhead. Because an object of type functor is passed to for_each, the compiler knows exactly which function to call: functor::operator(), and so it can be trivially inlined and will be just as efficient as your original loop.
C++0x will introduce lambda expressions which make a third form possible.
std::for_each(someVariable.begin(), someVariable.end(), [](Foo& arg){
blah(arg.x, arg.y);
woop(arg.z);
});
Finally, it will also introduce a range-based for loop:
for(Foo& arg : my_someVariable)
{
blah(arg.x, arg.y);
woop(arg.z);
}
So if you've got access to a compiler which supports subsets of C++0x, you might be able to use one or both of the last forms. Otherwise, the idiomatic solution (without using Boost) is to use for_eachlike in one of the two first examples.
By the way, MSVS 2008 has a "for each" C++ keyword. Look at How to: Iterate Over STL Collection with for each.
int main() {
int retval = 0;
vector<int> col(3);
col[0] = 10;
col[1] = 20;
col[2] = 30;
for each( const int& c in col )
retval += c;
cout << "retval: " << retval << endl;
}
Prefer algorithm calls to hand-written loops
There are three reasons:
1) Efficiency: Algorithms are often more efficient than the loops programmers produce
2) Correctness: Writing loops is more subject to errors than is calling algorithms.
3) Maintainability: Algorithm calls often yield code that is clearer and more
straightforward than the corresponding explicit loops.
Prefer almost every other algorithm to for_each()
There are two reasons:
for_each is extremely general, telling you nothing about what's really being done, just that you're doing something to all the items in a sequence.
A more specialized algorithm will often be simpler and more direct
Consider, an example from an earlier reply:
void print(int v)
{
std::cout << v << std::endl;
}
// ...
std::for_each(array.begin(), array.end(), print); // using STL
Using std::copy instead, that whole thing turns into:
std::copy(array.begin(), array.end(), std::ostream_iterator(std::cout, "\n"));
"struct functor {
void operator()(Foo& arg){
blah(arg.x, arg.y);
woop(arg.z);
}
};
std::for_each(someVariable.begin(), someVariable.end(), functor());"
I think approaches like these are often needlessly baroque for a simple problem.
do i=1,N
call blah( X(i),Y(i) )
call woop( Z(i) )
end do
is perfectly clear, even if it's 40 years old (and not C++, obviously).
If the container is always a vector (STL name), I see nothing wrong with an index and nothing wrong with calling that index an integer.
In practice, often one needs to iterate over multiple containers of the same size simultaneously and peel off a datum from each, and do something with the lot of them. In that situation, especially, why not use the index?
As far as SSS's points #2 and #3 above, I'd say it could be so for complex cases, but often iterating 1...N is often as simple and clear as anything else.
If you had to explain the algorithm on the whiteboard, could you do it faster with, or without, using 'i'? I think if your meatspace explanation is clearer with the index, use it in codespace.
Save the heavy C++ firepower for the hard targets.