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 to1
double f
set to1.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
Pointer Comparisons ">" with One Before the First Element of an Array Object
How to Do Performance Test Using the Boost Library for a Custom Library
Is There Any 'Out-Of-The-Box' 2D/3D Plotting Library for C++
Why Does Std::Vector Work with Incomplete Types in Class Definitions
Getting a List of User Profiles on a Computer in C++ Win32
Array of Size Defined by Not Constant Variable
C++11 Std::Async Doesn't Work in Mingw
Clang VS Gcc - Optimization Including Operator New
C++: Difference Between Member and Non Member Functions
Why Can't I Use Inheritance to Implement an Interface in C++
Correct Way to Define C++ Namespace Methods in .Cpp File
Emacs C++-Mode Incorrect Indentation
Breaking Out from Socket Select