почему основное выражение не включает template_id

#c #bnf

#c #bnf

Вопрос:

У меня есть такой код, скомпилируйте с помощью «g -Wall -g -std= c 11 test.cpp «, который не компилируется, потому что ошибка: ожидаемое первичное выражение перед токеном ‘)’

 #include <functional>
#include <vector>
#include <algorithm>

int main()
{
  std::vector<int> vec;
  for(int i=0;i<10;  i)
    {
      vec.push_back(i);
    }
  std::sort(vec.begin(),vec.end(),std::less<int>);  //should be std::less<int>()
}
  

Но стандарт гласит:

 primary-expression:
  literal
  this
  ( expression )
  id-expression
  lambda-expression

id-expression:
  unqualified-id
  qualified-id

unqualified-id:
  identifier
  operator-function-id
  conversion-function-id
  literal-operator-id
  ~ class-name
  ~ decltype-specifier
 template-id

template-id
  simple-template-id

simple-template-id
  template-name <template-argument-list> 
  

Итак, кажется, что std::less — это идентификатор шаблона, поэтому это первичное выражение.

Комментарии:

1. какой компилятор вы используете?

2. FWIW, Clang: ошибка: ожидается ‘(‘ для приведения в стиле функции или построения типа

3. @MantoshKumar, вероятно, GCC. 4.9 выдает ошибку.

4. Похоже, что проблема в сообщении об ошибке компиляции Clang. Я запустил ту же программу в VS2010 и получил следующую «ошибку C2275: ‘std::less<_Ty>’: незаконное использование этого типа в качестве выражения».

5. @MantoshKumar, в ошибке Clang нет ничего плохого. По сути, это говорит о том, что «у вас есть половина выражения этого типа, но вам не хватает другой половины».

Ответ №1:

Грамматическая корректность не обязательно делает программу семантически корректной. Создание грамматики из primary-expression -> template-id позволяет использовать специализацию шаблона функции в качестве выражения, например, это допустимо:

 template <typename T>
bool less(const Tamp; a, const Tamp; b) { return a < b; }

int main() {
  std::vector<int> vec;
  std::sort(vec.begin(), vec.end(), less<int>);
}
  

Однако идентификатор шаблона, который ссылается на шаблон класса, не может использоваться в качестве выражения.

Комментарии:

1. 1. Разница между семантикой и синтаксисом и в лучшие времена незаметна, а в C тем более. Стандарт не делает различий между различными типами плохо сформированных программ: он просто определяет хорошо сформированную программу как «программу на C , построенную в соответствии с правилами синтаксиса, диагностируемыми семантическими правилами и правилом единого определения», а плохо сформированную программу как программу, которая не является правильно сформированной.

2. @Casey. Я почти согласен с вами. Я думаю, что программа семантически неверна, но она является основным выражением, значит ли это, что g сообщает об ошибке неправильного типа? Кажется, что код ошибки clang «незаконное использование этого типа в качестве выражения» более разумный.

Ответ №2:

В этом разница между синтаксическим анализатором и семантическим анализатором. Грамматика C сообщает вам только то, что является грамматическим — то, что будет проходить через анализатор. Например, грамматика также позволит вам сделать что-то вроде:

 std::sort(vec.begin(), vec.end(), ~MyClass);
  

по той же причине — потому ~ class-name что это unqualified-id . Вам нужно посмотреть на семантические правила языка, чтобы определить, правильно ли сформирована программа, а не просто смотреть на грамматику, и семантические правила языка требуют здесь значения, а не типа.


В частности, я полагаю, что стандарт говорит об этом через правила для оператора вызова функции ( () ) в C 11 5.2.2 [expr.call] / 4: (выделение мое)

При вызове функции каждый параметр (8.3.5) должен быть инициализирован (8.5, 12.8, 12.1) соответствующим аргументом.

8.5 [dcl.init]/1: (курсив мой)

Декларатор может указать начальное значение для объявляемого идентификатора. Идентификатор обозначает инициализируемую переменную.

Но я не специалист по стандартам, и я не в комитете, так что YMMV.

Ответ №3:

Честно говоря, я не думал об этом с точки зрения выражений. Но то, как я думаю об этом — std::sort хочет объект для его третьего параметра. std::less<int> это просто объявление типа. std::less<int>() создает объект, который std::sort требуется.