4

Why it is not possible to define const and non-const variables in one definition list?

For example, in using for loop:

for (size_t i = 0, const iCount = data.size(); i < iCount; ++i);

It would be better from const-correctness viewpoint I guess.

P.S. I've asked this question wrong at first time. It is more for language designers rather than "why it can be compiled on my machine?". I wanted to say that this would be much better if it would be implemented as syntax sugar in next C++ standards. Also this will prevent calls of data.size() in each loop iteration. I mean, why not to extent current C++ variable definition list to support const and non-const in single definition list?

Victor Polevoy
  • 12,735
  • 7
  • 68
  • 134
  • possible duplicate of [Is it possible to declare two variables of different types in a for loop?](http://stackoverflow.com/questions/2687392/is-it-possible-to-declare-two-variables-of-different-types-in-a-for-loop) – Cory Kramer Mar 02 '15 at 13:55
  • 2
    It isn't the `const` that is the problem (necessarily) it is the two different types. – Cory Kramer Mar 02 '15 at 13:55
  • @w.b Well I did not say it is. The only thing I wanted to say is "Okay, it is different types, but why it can be a sugar syntax, in new standard, for example"? – Victor Polevoy Mar 02 '15 at 14:00
  • Your question was "why it is not possible..." and my answer was "it is illegal C++ syntax". Why the C++ standard committee decided to do this is another conversation entirely. – Cory Kramer Mar 02 '15 at 14:08
  • @Cyber, the C++ committee didn't decide it, the declarator grammar comes from C. – Jonathan Wakely Mar 02 '15 at 14:09
  • Yes, I've asked it wrong. But when I realized that a lot of people have already answered so I did not edit the question because of being late. – Victor Polevoy Mar 02 '15 at 14:09
  • 3
    @Cyber: The problem *is* the `const` since, unlike some other modifiers, the declaration syntax doesn't allow you to add that to an individual declarator. Two different types aren't necessarily forbidden: `int i = 0, *p = &i;` is a perfectly cromulent declaration. – Mike Seymour Mar 02 '15 at 14:13

5 Answers5

2

You can't since you can only have one type in the for loop declaration. const is part of the type.

Bathsheba
  • 220,365
  • 33
  • 331
  • 451
  • It's a valid question though, as you can do e.g. `for (int i = 0, *j = &i; ...)` and `i` and `j` have different types. – Jonathan Wakely Mar 02 '15 at 14:03
  • But `*j` is the same type as `i`: `j` is a *pointer* to an `int` type. Indeed, it is a good question, which is why I upvoted it. – Bathsheba Mar 02 '15 at 14:05
2

In my opinion it is simply a convention. It could be adopted that qualifiers might be included in declarators.

At present you may use cv-qualifiers with pointer declarators. For example such construction is valid

int x, * const p = &x;

So I do not see serious reasons why this construction

int x, const y = 10;

could not be allowed.

You should ask this question at isocpp.org where the C++ Standard is discussed.:)

Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268
  • Thanks, that was the type of question I expected to see. – Victor Polevoy Mar 02 '15 at 14:20
  • The reason why this one works is because the type of _p_ is `const pointer to int`, not `pointer to const int`. Thus `*p` still has type `int`, thus it passes compilation. – haavee Mar 02 '15 at 14:37
  • @haavee But the declaration doesn't declare something with a mysterious name `*p`, it declares something with the name `p`. And the type of `p` is different from that of `x`. – Angew is no longer proud of SO Mar 02 '15 at 14:42
  • According to the standard they are not. If you read http://en.cppreference.com/w/cpp/language/declarations carefully it sais that `*` (pointer-to) is not part of the _decl-specifier-seq_. It is a tough read that document but it's all there. – haavee Mar 02 '15 at 14:58
  • @haavee Yes, `*` is not part of the *decl-specifier-seq*, but the type is controlled by more than the *decl-specifier-seq*. `x` and `p` still have different type. `std::is_same::value` is `false`. – Angew is no longer proud of SO Mar 02 '15 at 16:24
1

I wanted to say that this would be much better if it would be implemented as syntax sugar in next C++ standards.

"Syntactic sugar causes cancer of the semi-colon."

Adding a "simple" change like that has a huge cost, in terms of complexity of the specification, complexity of compiler implementations, complexity of IDEs and code analysis tools, and doesn't necessarily make the language any easier to teach or use, except in the one specific case you've shown.

Also this will prevent calls of data.size() in each loop iteration.

Have you checked whether there really are multiple calls in optimized code? If there aren't, why do we need a language extension to prevent something that doesn't happen?

I mean, why not to extent current C++ variable definition list to support const and non-const in single definition list?

It wouldn't be widely useful anywhere except a for loop, and you can do it easily anyway:

{
  const size_t iCount = data.size();
  for (size_t i = 0; i < iCount; ++i)
    ;
}
Jonathan Wakely
  • 153,269
  • 21
  • 303
  • 482
  • I agree with anything but in last code snippet the `iCount` variable has 2 minor bad things in my opinion: at first it's scope is not only `for` loop but entire outer scope and second is that it needs one useless line of code. – Victor Polevoy Mar 02 '15 at 14:20
  • 2
    The extra braces are there to make the scope identical. Sometimes trying to squeeze everything onto one line doesn't help clarity, especially if you have multiple declarations, and even more so when they have different types. So it's debatable if that extra line is useless, or actually makes the code easier to read. – Jonathan Wakely Mar 02 '15 at 14:28
  • Well, I did not pay attention to the extra braces in the snippet :) But, if we usually use `for` loop with one definition of "start" variable like `i` in the snippet I'd expect also to see `end` variable definition near it. Maybe it's just me but I see some use here. Also it will not require 2 extra braces :) Okay, thank you for your answer. – Victor Polevoy Mar 02 '15 at 14:31
0

Inside a for you can declare multiple variables provided they have the same type. size_t and const size_t are different types.

You don't need to declare iCount there, just write ; i < data.size(); as the condition.

Luchian Grigore
  • 236,802
  • 53
  • 428
  • 594
  • Then it will perform `data.size()` call in each iteration. Or am I wrong? – Victor Polevoy Mar 02 '15 at 13:57
  • 1
    @VictorPolevoy Probably not if compiled with optimizations. https://stackoverflow.com/questions/16945294/is-it-expensive-to-compute-vector-size-in-for-loops-each-iteration – Cory Kramer Mar 02 '15 at 13:57
  • 1
    @VictorPolevoy probably not, and even if it did, would it matter? – Luchian Grigore Mar 02 '15 at 14:03
  • I think excess calls always matter. In this case - maybe not but think in optimizations. Of course we can move this calculations and assignments before the loop in this case but I am asking here about simplicity. Like in python. Also it will cost a few lines of code :) My question is about "why **not** to implement this? I think it would be useful". – Victor Polevoy Mar 02 '15 at 14:06
  • 2
    @VictorPolevoy nope, they only matter when they actually effect performance. In my experience, 99% of the time you're better off writing readable code, rather than worrying about an extra call which is likely optimized away anyway. As to the "why", that's a question for the language designers. – Luchian Grigore Mar 02 '15 at 14:08
0

Because they are different data types and thus it's not a single definition list.

haavee
  • 4,111
  • 19
  • 21
  • But `size_t i, *j;` declares two variables of different types. – Jonathan Wakely Mar 02 '15 at 14:02
  • It's the _cv_-qualifier ('const/volatile) that makes it different. One can read `*j` as "j is a variable that, when de-referenced, yields a type of size_t". – haavee Mar 02 '15 at 14:09
  • 1
    Yep, and so `i` and `j` are variables of different types. – Jonathan Wakely Mar 02 '15 at 14:10
  • You can also do `for (int i=0, j[2] = {0, 1};` where `i` and `j` again have different types. – Jonathan Wakely Mar 02 '15 at 14:12
  • Quoth http://en.cppreference.com/w/cpp/language/declarations: _Each init-declaractor in an init-declarator sequence S D1, D2, D3; is processed as if it were a standalone declaration with the same specifiers: S D1; S D2; S D3;._ – haavee Mar 02 '15 at 14:25
  • 1
    Right, so the rule is not that you can't have different data types, since the init-declarators D1 and D2 can produce different types. – Jonathan Wakely Mar 02 '15 at 14:29
  • That's not how I read this; as far as I understand it means that all _D1 ... Dn_ must evaluate to the same Lvalue type _S_. E.g. a specific _Dm_ could also declare a function which returns `size_t`. – haavee Mar 02 '15 at 14:35