In C++ Why Can't I Write a For() Loop Like This: For( Int I = 1, Double I2 = 0;

In C++ why can't I write a for() loop like this: for( int i = 1, double i2 = 0;

int i = 1, double i2 = 0; is not a valid declaration statement, so it cannot be used inside the for statement. If the statement can't stand alone outside the for, then it can't be used inside the for statement.

Edit:
Regarding your questions about comma operators, options 'A' and 'B' are identical and are both valid. Option 'C' is also valid, but will probably not do what you would expect. z will be assigned 1, and the statements 3 and 4 don't actually do anything (your compiler will probably warn you about "statements with no effect" and optimize them away).

Update:
To address the questions in your edit, here is how the C++ spec (Sec 6.5) defines for:

for ( for-init-statement condition(opt) ; expression(opt) ) statement

It further defines for-init-statement as either expression-statement or simple-declaration. Both condition and expression are optional.

The for-init-statement can be anything that is a valid expression-statement (such as i = 0;) or simple-declaration (such as int i = 0;). The statement int i = 1, double i2 = 0; is not a valid simple-declaration according to the spec, so it is not valid to use with for. For reference, a simple-declaration is defined (in Section 7) as:

attribute-specifier(opt) decl-specifier-seq(opt) init-declarator-list(opt) ;

where decl-specifier-seq would be the data type plus keywords like static or extern and init-declarator-list would be a comma-separated list of declarators and their optional initializers. Attempting to put more than one data type in the same simple-declaration essentially places a decl-specifier-seq where the compiler expects a init-declarator-list. Seeing this element out of place causes the compiler to treat the line as ill-formed.

The spec also notes that the for loop is equivalent to:

{
for-init-statement
while ( condition ) {
statement
expression ;
}
}

where condition defaults to "true" if it is omitted. Thinking about this "expanded" form may be helpful in determining whether a given syntax may be used with a for loop.

Why is it so 'hard' to write a for-loop in C++ with 2 loop variables?

You just have to understand the first statement is a declaration (and that comma is not the comma operator). It's not any harder to do:

for (int i, double d; ...)

Than it is:

int i, double d;

Because for (init cond; expr) statement gets expanded to:

{
init
while (cond)
{
statement
expr;
}
}

A trick is to make that init statement a struct definition and instance, like:

for (struct { int myIndex; MyElement* ptr;} data = {0, Pool->First};
data.ptr;
++data.myIndex, data.ptr = data.ptr->next)
{
// blah...
}

Which becomes the same as:

{
struct
{
int myIndex;
MyElement* ptr;
} data = {0, Pool->First};

while (data.ptr)
{
{
// blah...
}
++data.myIndex, data.ptr = data.ptr->next;
}
}

But I find that pretty ugly. In practice, I'd just split it up like you have. If scope is really a problem, which it probably isn't, throw the extra braces around there.

I don't think there's much to improve here without a bit of boilerplate code.

Why c++ does not support multiple initializers in for loop?

In C++ grammar, different data types are separated with ; (if not function). In for loop, once the ; is found the meaning is changed. i.e.

for (<initializations>; <condition>; <next operation>)

Other reason is possibly to avoid complexity in an already complex grammar, this feature is not allowed.

If you want to declare variables in for loop scope, then you can always simulate that situation:

int main()
{
{
double j = 3.0;
for (int i = 0; i < 10; i++, j+=0.1)
cout << i << j << endl;
}
return 0;
}

How do I declare several variables in a for (;;) loop in C?

You can (but generally shouldn't) use a local struct type.

for ( struct { int i; char* ptr; } loopy = { 0, bam };
loopy.i < 10 && * loopy.ptr != 0;
++ loopy.i, ++ loopy.ptr )
{ ... }

Since C++11, you can initialize the individual parts more elegantly, as long as they don't depend on a local variable:

for ( struct { int i = 0; std::string status; } loop;
loop.status != "done"; ++ loop.i )
{ ... }

This is just almost readable enough to really use.


C++17 addresses the problem with structured bindings:

for ( auto [ i, status ] = std::tuple{ 0, ""s }; status != "done"; ++ i )

Are multiple conditions allowed in a 'for' loop?

The condition

i < p, j < q

is allowed but probably isn't what was intended as it discards the result of the first expression and returns the result of j < q only. The comma operator evaluates the expression on the left of the comma, discards it then evaluates the expression on the right and returns it.

If you want to test for multiple conditions use the logical AND operator && instead

i < p && j < q

How to use double in a for loop rather than an int?

You could do something like this:

public static void FindTheDouble() {

double LookFor = 2.29195;

for (double i = 1.0; i <= 5.0; i+=0.00005) {
System.out.println(i);
if (i == LookFor) {
System.out.println();
System.out.println("Found the double: "+LookFor);
break;
}
}
}

Your break statement is correct.

Your equality statement might fail with doubles. Instead you want to do something like this:

if (Math.abs((i - LookFor)) < 0.0000001)

The double can have extraneous values at extended decimal places that can interfere with the success of your equality comparison. Instead it is better to check that the two double values are within some degree of precision that is acceptable to you.

Why is this C++ working? (declaration/definition of variables)

Because that’s how scopes in C++ work: the scope of these variables is the body of the for loop. In other words: they are created inside each loop iteration and live until the end of that same iteration.

It’s entirely equivalent to how you can declare local variables inside a function even if you call a function multiple times:

int f(int x) {
int a = x * 2;
return a;
}

int main() {
f(2);
f(2);
}

Surely this does not surprise you, and you don’t think that a inside f is somehow redefined?

Multiple initialization in C# 'for' loop

It can't be done. Put one of the declarations before the loop:

MyClass i = 0;
for (int j = 1; j < 3; j++, i++)

Or for symmetry, both of them:

MyClass i = 0;
int j = 1;
for (; j < 3; j++, i++)

It's also possible that one of the variables is more primary than the other. In that case it might be neater to have one be the loop variable, and deal with the other seperately, like this:

MyClass i = 0;
for (int j = 0; j < 3; j++)
{
...
i++;
}

Note that if i and j were of the same type, then you could declare them both in the for-loop:

for (int i = 0, j = 1; j < 3; j++, i++)

Is it possible to declare two variables of different types in a for loop?

C++17: Yes! You should use a structured binding declaration. The syntax has been supported in gcc and clang since gcc-7 and clang-4.0 (clang live example). This allows us to unpack a tuple like so:

for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
// ...
}

The above will give you:

  • int i set to 1
  • double f set to 1.0
  • std::string s set to "ab"

Make sure to #include <tuple> for this kind of declaration.

You can specify the exact types inside the tuple by typing them all out as I have with the std::string, if you want to name a type. For example:

auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}

A specific application of this is iterating over a map, getting the key and value,

std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
// ...
}

See a live example here


C++14: You can do the same as C++11 (below) with the addition of type-based std::get. So instead of std::get<0>(t) in the below example, you can have std::get<int>(t).


C++11: std::make_pair allows you to do this, as well as std::make_tuple for more than two objects.

for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}

std::make_pair will return the two arguments in a std::pair. The elements can be accessed with .first and .second.

For more than two objects, you'll need to use a std::tuple

for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
std::cout << std::get<1>(t) << '\n'; // cout Hello world
std::get<2>(t).push_back(std::get<0>(t)); // add counter value to the vector
}

std::make_tuple is a variadic template that will construct a tuple of any number of arguments (with some technical limitations of course). The elements can be accessed by index with std::get<INDEX>(tuple_object)

Within the for loop bodies you can easily alias the objects, though you still need to use .first or std::get for the for loop condition and update expression

for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
auto& i = std::get<0>(t);
auto& s = std::get<1>(t);
auto& v = std::get<2>(t);
std::cout << s << '\n'; // cout Hello world
v.push_back(i); // add counter value to the vector
}

C++98 and C++03 You can explicitly name the types of a std::pair. There is no standard way to generalize this to more than two types though:

for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}


Related Topics



Leave a reply



Submit