Шаблон в шаблоне: почему «>>» должно быть `>> в списке аргументов вложенного шаблона» - PullRequest
47 голосов
/ 14 июля 2011

Я знаю, что когда мы используем шаблон внутри другого шаблона, мы должны написать его так:

vector<pair<int,int> > s;

и если мы напишем это без пробела:

vector<pair<int,int>> s;

мы получим ошибку:

`>> 'должно быть`>>' в списке аргументов вложенного шаблона

Я вижу, что это понятно, но я просто не могу не задаться вопросом, в каких случаях это будет действительно неоднозначно?

Ответы [ 8 ]

48 голосов
/ 14 июля 2011

Иногда вы хотите , чтобы это было >>.Рассмотрим

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

В C ++ 03 это успешно анализирует и создает массив размером 256.

26 голосов
/ 14 июля 2011

Это никогда не будет двусмысленным. Это подтверждается тем фактом, что в C ++ 0x вам больше не нужно писать пробел между закрывающим шаблоном > s.

Дело в том, что компиляторы предпочли бы маркировать ввод как можно более независимым от контекста. Так как C ++ в любом случае не является контекстно-независимым языком, добавление только этого особого случая не усложнит ситуацию.

10 голосов
/ 14 июля 2011

В текущем стандарте токенизация является жадной, поэтому >> будет обрабатываться как один токен, так же как a +++ b будет обрабатываться как a ++ + b.Это изменило и новый стандарт.Хотя это требует больше работы от разработчиков компиляторов, было сочтено, что в целом оно того стоит (и некоторые крупные компиляторы уже реализуют это как расширение в любом случае).

6 голосов
/ 14 июля 2011

C ++ действительно невероятно трудно разобрать - гораздо сложнее, чем большинство других языков. Это очень непротиворечивый язык, но между токенизацией ввода и пониманием грамматического анализа синтаксиса делается так много работы, что вещи, которые кажутся простыми для компилятора, часто НЕ являются.

Исторический оператор ">>" является оператором. Он «идентифицируется», поскольку исходный файл разбит на токены. Затем эти токены впоследствии «понимаются» в некотором контексте во время грамматического анализа (еще долго после завершения токенизации).

Если вы провели грамматический анализ , в то время как вы токенизировали, то у вас есть «подсказки», помогающие отличить то, что «>>» следует рассматривать как два замыкания для объявления шаблона (или определения). Однако исторически сложилось так, как работают исторические компиляторы C ++. (Новые компиляторы делают больше обратной связи между грамматическим анализом и токенизацией, включая больше «заблаговременных действий», чтобы помочь устранить эти неоднозначности.)

Да, новый стандарт C ++ 0x меняет это и заставляет производителей компиляторов переписывать свои реализации, чтобы устранить неоднозначность ">>" в вашем случае. Таким образом, это никогда не будет двусмысленным в будущем. Однако старые компиляторы C ++ не могут справиться с этим, поэтому может считаться «хорошей практикой», чтобы ваш код оставался совместимым с пробелом между символами «>».

1 голос
/ 19 июля 2015

Чтобы избежать этой ошибки, установите соответствующий диалект C ++.Например, с gcc 4.9 следующий файл не компилируется с g++:

#include <vector>
#include <utility>

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

Давайте разберемся со всем:

#include <iostream>

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

Скомпилировано только с g++ test.cpp thisпечатает код 199711. Хотя gcc 4.9 был выпущен в 2014 году, диалект C ++ по умолчанию - C ++ 98 с расширениями GNU.C ++ 98 требует от нас написать vector<pair<int, int> >.Если вам нравится vector<pair<int, int>>, больше скомпилируйте с -std=c++11 или -std=gnu++11.

1 голос
/ 14 июля 2011

Это зависит от компилятора.Visual Studio не требует этого, то есть оба работают, пока g ++ выдает ошибку.Я думаю, что это зависит от реализации компилятора.

0 голосов
/ 22 июня 2019

Синтаксис потока

cin >> var;

Vs

Синтаксис вложенного шаблона

For<Bar<Barz>>

Первая фаза компилятора, лексический анализатор не сможет распознать.

0 голосов
/ 16 сентября 2016

У меня была эта проблема при программировании класса на c ++, и я решил ее, выполнив следующее:

Строка, которая вызвала ту же ошибку, упомянутую здесь ранее:

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

Строка, прошедшая через кросс-компилятор GCC и работающая:

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

Для меня это была просто ошибка в интерпретации высказывания.

...