【问题标题】:why primary expression don't include template_id为什么主表达式不包含 template_id
【发布时间】:2014-08-17 15:02:53
【问题描述】:

我有这样的代码,用“g++ -Wall -g -std=c++11 test.cpp”编译,由于错误:预期的primary-expression before')'标记而无法编译

#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 是一个模板 ID,所以它是一个主表达式。

【问题讨论】:

  • 你使用的是哪个编译器?
  • FWIW, Clang: error: expected '(' for function-style cast or type construction
  • @MantoshKumar,可能是 GCC。 4.9 给出了错误。
  • 嗯,看起来 Clang 编译错误消息中存在问题。我在 VS2010 中运行相同的程序并得到以下“错误 C2275:'std::less<_ty>':非法使用这种类型作为表达式”。
  • @MantoshKumar,Clang 错误没有任何问题。它基本上是在说“你有一半这种类型的表达,但你缺少另一半”。

标签: c++ bnf


【解决方案1】:

这就是解析器和语义分析器的区别。 C++ 的语法只告诉你什么是合乎语法的——什么将通过解析器。例如,语法还允许您执行以下操作:

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

出于同样的原因——因为~ class-nameunqualified-id。您需要查看语言的语义规则来确定程序是否格式良好,而不仅仅是看语法,并且语言的语义规则在这里需要一个值,而不是类型。


具体来说,我相信标准是通过 C++11 5.2.2 [expr.call]/4 中的函数调用运算符 (()) 的规则来说明这一点的:(强调我的)

调用函数时,每个参数 (8.3.5) 都应初始化 (8.5, 12.8, 12.1)及其对应的论据。

8.5 [dcl.init]/1:(强调我的)

声明者可以为被声明的标识符指定一个初始值。 标识符指定正在初始化的变量

但我不是标准学者,也不是委员会成员,所以 YMMV。

【讨论】:

    【解决方案2】:

    语法正确并不一定使程序语义正确。从 primary-expression -> template-id 产生的语法允许使用函数模板的特化作为表达式,例如,这是有效的:

    template <typename T>
    bool less(const T& a, const T& b) { return a < b; }
    
    int main() {
      std::vector<int> vec;
      std::sort(vec.begin(), vec.end(), less<int>);
    }
    

    但是,引用类模板的模板 ID 不能用作表达式。

    【讨论】:

    • +1。语义和语法之间的区别在最好的时候是微妙的,在 C++ 中更是如此。该标准没有区分不同风格的非良构程序:它只是将良构程序定义为“根据语法规则、可诊断语义规则和单一定义规则构造的 C++ 程序”,以及一个良构程序。程序作为一个格式不正确的程序。
    • @Casey。我几乎同意你的看法。我认为程序在语义上是错误的,但它确实是一个主要的表达方式,所以这是否意味着 g++ 报告了错误类型的错误?看来 clang 的错误代码“非法使用这种类型作为表达式”更合理。
    【解决方案3】:

    老实说,我还没有从表达的角度考虑过这一点。但我的想法是——std::sort 想要一个对象作为它的第三个参数。 std::less&lt;int&gt; 只是一个类型声明。 std::less&lt;int&gt;() 创建 std::sort 需要的对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-25
      • 1970-01-01
      • 2014-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多