56

I know that when we are using template inside another template, we should write it like this:

vector<pair<int,int> > s;

and if we write it without the whitespace:

vector<pair<int,int>> s;

we will get an error:

`>>' should be `> >' within a nested template argument list

I see this is understandable, but I just can't help but wondering, in which cases will this be really ambiguous?

svick
  • 236,525
  • 50
  • 385
  • 514
zw324
  • 26,764
  • 16
  • 85
  • 118
  • 5
    I think the reason is simply because it is so hard to parse: `vector < pair < int, int >> s;` could be `(vector < pair < int),(int >> s);` – Seb Holzapfel Jul 14 '11 at 14:59
  • Related: [For nested templates, when did \`>>\` become standard C++ (instead of \`> >\`)?](https://stackoverflow.com/q/7087033) - C++11 – Peter Cordes Jun 22 '21 at 13:27

8 Answers8

52

Sometimes you want it to be >>. Consider

boost::array<int, 1024>>2> x;

In C++03 this successfully parses and creates an array of size 256.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 7
    But you can disambiguate this in C++0x as well: `boost::array>2)> x;` – Armen Tsirunyan Jul 14 '11 at 15:08
  • 2
    @Armen indeed you can. But it is one case where it is "ambiguous", in the way that the program is valid when interpreted as C++03 meaning. – Johannes Schaub - litb Jul 14 '11 at 15:09
  • 2
    This is indeed very interesting. But still this isn't ambiguous in that the only interpretation of >> that would yield a valid construct is >> as shift. If you treat it as two closing > it is invalid. Is there actually an example where both interpretations would yield valid constructs? – Armen Tsirunyan Jul 14 '11 at 15:11
  • 2
    @Armen right. I interpreted "ambiguous" different than what one would expect it would mean, hence I put it in '"'es. The questioner seems to have asked "in what case would it make sense to treat it as >>?". There are real ambiguous cases (recently one test case was shown in the "Ways to return true on C++0x and false on C++03", and IIRC, one testcase is shown in the paper proposing the angle-brackets change for C++0x). – Johannes Schaub - litb Jul 14 '11 at 15:15
  • I was thinking about that too... Makes sense. Which makes my answer incorrect and yours correct. But I won't remove it. +1 :) – Armen Tsirunyan Jul 14 '11 at 15:16
  • No sane person wants it that way. Even if you're insane you should prefer `boost::array>2)> x;` which breaks the ambiguity. Besides, even without that, it should be disambiguated as "array> 2)> x;" makes sense and "array (2> x);" can be checked for as a silly case that no program should have. I DONT WANT TO PUT EXTRA SPACES IN MY TEMPLATES, IT CAUSES INCONSISTANT CODE. – Dmytro Sep 03 '16 at 06:45
  • This piece of code also create an array of size 256 with `g++ -std=c++98` in my test. – bigeast Mar 06 '17 at 03:38
  • is the following potentially valid? `( (templated::thing)>2)> x;` If so, that could be a valid interpretation of the given example. – bean Oct 17 '18 at 23:25
  • @bean `boost::array` is a type template, therefore that's not a valid interpretation for my example. – Johannes Schaub - litb Oct 21 '18 at 12:10
  • @Johannes what about ignoring the fact that boost::array is something and just considering the given syntax itself? (that's why i wrote templated::thing instead.) I.e., could there be a templated::thing where `( (templated::thing)>2)> x;` is valid syntax? I'm just questioning whether >> as a shift is the only valid interpretation of the given syntax. – bean Oct 21 '18 at 15:07
  • @bean whether you put parentheses is very important, because it breaks >> up into two tokens. So, if "thing" is a function template, your example code is valid syntax. And if there is a suitably overloaded `operator>` it might even compile. But I don't see the relevance to my example. – Johannes Schaub - litb Oct 21 '18 at 20:44
  • @JohannesSchaub-litb the point of the original question is purely about syntax and ambiguity with respect to single vs double token interpretation of >> by the compiler. As such (ignoring the fact that boost::array is actually a thing wherein the given addition of parenthesis would not make sense), I was pointing out that there may be an alternate tokenization of your given example where the raw syntax could potentially be valid (w.r.t. syntax only), in contrast to a comment above wherein it is suggested that the only valid interpretation of your example is the intended one. – bean Oct 23 '18 at 06:27
30

It won't ever be ambiguous. This is proven by the fact that in C++0x you don't have to write a space between closing template >s any more.

The thing is that the compilers would prefer to tokenize the input as context-independently as possible. Since C++ is not a context independent language anyway, adding just this one special case isn't going to make things particularly harder.

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • Thanks! Though I use C++0x compiler everyday (not for this code), I really don't know much about it. Thanks for the tip:) – zw324 Jul 14 '11 at 15:20
  • @Ziyao Wei: You're welcome, but you should really accept @Johannes's answer, because mine is simply wrong :) – Armen Tsirunyan Jul 14 '11 at 15:45
11

In the current standard, tokenization is greedy, so >> will be processed as a single token, in the same way that a +++ b will be parsed as a ++ + b. This has changed and the new standard. While it requires more work from the compiler implementors, it was deemed that overall it is worth it (and some major compilers already implement that as an extension anyway).

idmean
  • 14,540
  • 9
  • 54
  • 83
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
7

C++ is really incredibly hard to parse -- much more difficult than most other languages. It is a very consistent language, but so much work is done between tokenizing the input and understanding the grammatical analysis of the syntax, that things that seem like they should be simple for a compiler, often are NOT.

The historical ">>" operator is an operator. It is "identified" as the source file is broken into tokens. Those tokens are then later "understood" in some context during grammatical analysis (long after tokenization is complete).

If you did grammatical analysis while you tokenized, then you have "helps" to assist in the distinction that ">>" should be considered as two closures to a template declaration (or definition). Yet, this is historically not how historical C++ compilers work. (New compilers do more feedback between grammatical analysis and tokenization, including more "look-aheads" to help resolve these ambiguities.)

Yes, the new C++0x standard changes that, and forces compiler vendors to re-write their implementations to disambiguate ">>" in your case. So, it will never be ambiguous going forward. However, older C++ compilers cannot handle that, so it may be considered "good practice" to keep your code compatible with the space between the '>' characters for now.

charley
  • 5,913
  • 1
  • 33
  • 58
5

Avoid this error by setting an appropriate C++ dialect. For example, with gcc 4.9 the following file does not compile with g++:

#include <vector>
#include <utility>

int main()
{
    using namespace std;
    vector<pair<int, int>> v; // compile error!
    return 0;
}

Let's get to the bottom of things:

#include <iostream>

int main()
{
    std::cout << __cplusplus << std::endl;
    return 0;
}

Compiled with just g++ test.cpp this code prints 199711. Although gcc 4.9 was released in 2014 the default C++ dialect is C++98 with GNU extensions. C++98 requires us to write vector<pair<int, int> >. If you like vector<pair<int, int>> more compile with -std=c++11 or -std=gnu++11.

Andreas Spindler
  • 7,568
  • 4
  • 43
  • 34
1

It depends on the compiler. Visual Studio does not mandate this i.e. both works while g++ produces an error. I think that this depends on the compiler implementation.

iBrAaAa
  • 394
  • 2
  • 14
0

I had this issue programing a class in c++, and i solved it by doing the following:

Line that produced the same error mentioned here before:

findAndDrawContoursFrame(cv::Mat&,cv::Mat&,std::vector<std::vector<cv::Point»&);

Line that passed through GCC Cross Compiler and Worked:

findAndDrawContoursFrame(cv::Mat&,cv::Mat&,std::vector< std::vector<cv::Point> >&);

For me it was just an error on the interpretation of the statement.

J. Chomel
  • 8,193
  • 15
  • 41
  • 69
0

Stream Syntax

cin >> var;

Vs

Nested Template Syntax

For<Bar<Barz>>

First phase of Compiler, lexical analyser will not be able to recognise.

Mani
  • 2,599
  • 4
  • 30
  • 49