29

I knew that if we don't put space after closing angle brackets in a variable declaration, C++ throws the following error.

‘>>’ should be ‘> >’ within a nested template argument list

But the error doesn't come if I use #define like in this code. Can someone explain me this?

I think #define is just a macro expansion and works like find-replace, so both the ways of declaring variable here should be identical.

Also this error doesn't occur if I compile it with C++11.

#include <bits/stdc++.h>
using namespace std;

#define vi vector<int>

int main(){
    //Doesn't work, compile error
    vector<vector<int>> v;

    //Works
    vector<vi> vv;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jignesh
  • 555
  • 1
  • 8
  • 18
  • 15
    In C++11 `>>` became valid, via a special rule, because the space requirement was such an annoyance. – Cheers and hth. - Alf Feb 17 '15 at 10:02
  • You want to know, why the macro works? I didn't see a question here. – Aitch Feb 17 '15 at 10:04
  • 1
    yes I want to know why the macro works – Jignesh Feb 17 '15 at 10:05
  • 3
    If you run `cpp` over the file, you can see that a space is added between the two `>` characters. – TartanLlama Feb 17 '15 at 10:06
  • @TartanLlama: And that's misleading. The preprocessor formally tokenizes, and the only spaces it leaves are within strings. Mike's answer is correct. – MSalters Feb 17 '15 at 13:04
  • 6
    @MSalters It's not misleading, it's diagnostic. When an integrated preprocessor feeds tokens directly to translation phase 7, whitespace is not explicitly represented. But when asked to generate textual output, the preprocessor _must_ insert whitespace when necessary to preserve token boundaries. Modern preprocessors will do this only when they have to. So, when you see whitespace in textual preprocessor output that wasn't there in the original, you can conclude there's some rule requiring the things on either side of it to remain distinct tokens. – zwol Feb 17 '15 at 14:35
  • 2
    @Jignesh Unrelated nitpick on your code: you should `#include `. The headers under `bits/` are not meant to be used directly. – zwol Feb 17 '15 at 14:37
  • 1
    @zwol I have been using this bits/stdc++.h for quite some time as a shortcut for not including different headers, it might not be optimal, but what problem can it cause, can you elaborate? – Jignesh Feb 17 '15 at 15:42
  • 5
    @Jignesh It's a g++ implementation detail. There's no guarantee it will still be there or do the same thing in the future, and no other compiler has it. – zwol Feb 17 '15 at 15:49
  • 3
    @Jignesh For instance, if I try to compile your test program with clang instead of g++ I get an error message, `test.cc:1:10: fatal error: 'bits/stdc++.h' file not found`. – zwol Feb 17 '15 at 15:50
  • 3
    Regarding stdc++ - [How does #include work in C++?](http://stackoverflow.com/questions/25311011/how-does-include-bits-stdc-h-works-in-c) – Bernhard Barker Feb 17 '15 at 15:51

1 Answers1

36

Macro expansion happens after tokenisation; it doesn't replace text, but sequences of tokens.

This means that, with the macro, the expansion of vi gives a > token, separate from the one following the macro invocation. In each case, tokenisation only finds a single > character, so that's the resulting token.

Without a macro, the "greedy" tokenisation rule meant that the two consecutive characters were treated as a single >> token, until C++11 added a special rule for this case.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 8
    To see this more clearly, consider `#define plusi +i`. You can now write `int i = 0; std::cout << +plusi`. Predict what happens and then try. – MSalters Feb 17 '15 at 13:06
  • 2
    @MSalters OTOH, anyone putting that into production needs to be sacked – Cole Tobin Feb 17 '15 at 14:13
  • This is a bit counterintuitive considering that there is a separate preprocessor program, `cpp`, that will output plain text. I would have assumed that explicitly preprocessing, then compiling afterwards, would be the same as letting the compiler itself do the preprocessing. – Szabolcs Feb 17 '15 at 17:27
  • 7
    [This experiment](http://pastebin.com/1MDWQZ73) shows that the preprocessor is being pretty smart about it. When using `cpp` to preprocess the code, it does indeed produce `vector >` with that space included. In other contexts it does not include the space. – Szabolcs Feb 17 '15 at 17:31