【问题标题】:GCC's two unusual error messagesGCC 的两条异常错误信息
【发布时间】:2011-03-14 11:09:39
【问题描述】:

今天,我遇到了两条以前从未见过的错误消息。这对我来说是全新的。

代码如下:

template<typename T>
struct adder { adder(const T &item) { } };

template<typename T>
void initializer(const T &item) {  adder<T>(item); }

int main() 
{
   initializer("const string literal");
}

在编译时,GCC 给出以下错误:

prog.cpp:在函数 'void initializer(const T&)' 中:
prog.cpp:6:错误:'adder item' 的声明隐藏了参数
prog.cpp:在函数'void initializer(const T&) [with T = char [21]]'中:
prog.cpp:10:从此处实例化
prog.cpp:6:错误:'adder item' 的声明隐藏了参数
prog. cpp:6: 错误:没有匹配函数调用'adder::adder()'
prog.cpp:3:注意:候选者是:adder::adder(const T&) [with T = char [21]]
prog.cpp:3: 注意:adder::adder(const adder&)


查看粗体字。一个错误显示两次,就是这个

错误:“adder item”的声明遮蔽了参数
错误:‘adder item’的声明隐藏了一个参数

这是什么意思?为什么它用不同的模板参数显示两次?第一个是T,第二个是char [21]

编辑:adder&lt;T&gt;(item) 是否声明名称为 item 的变量?但这不是我的本意。我认为它应该创建一个临时对象,将 item 作为参数传递给构造函数。

我想知道标准中处理此问题的部分!


其他有趣的错误是这样的:

错误:没有匹配的函数调用'adder::adder()'

这表明编译器正在寻找默认构造函数?但我想知道为什么编译器要寻找它,而实际上我的代码在第 6 行没有使用它


ideone 代码:http://www.ideone.com/jrdLL

【问题讨论】:

  • adder&lt;T&gt;(item) 表示adder&lt;T&gt; item; - 然后这两个错误才有意义。
  • 我编辑了我的答案,看看吧"

标签: c++ gcc diagnostics


【解决方案1】:

这表明编译器正在寻找默认构造函数?但我想知道为什么编译器会在实际上我的代码在第 6 行没有使用它时寻找它?

因为编译器认为你声明了名称为 item 的局部变量。

http://codepad.org/YBPKCvmm

【讨论】:

    【解决方案2】:

    了解正在发生的事情的关键是要意识到: 加法器(项目); 是一个名为 item 并具有类型的局部变量的定义 加法器;括号是多余的,但完美 允许的。如果你想调用构造函数,你将拥有 消除歧义 解释为数据定义,例如: 加法器((项目)); (我不确定这可能有什么用。它构建了一个临时的 加法器的对象,然后在结束时销毁它 表达。)

    一旦声明,实际的错误消息应该清楚(er) 理解为数据声明:函数参数是 就好像它们是在顶层块中定义的一样对待 函数,所以 adder(item) 是重复的(并且是矛盾的) 定义,加法器没有默认构造函数,所以 你不能在不提供参数的情况下定义它的实例。

    【讨论】:

    • 一个错误出现两次的事实:编译器解析模板定义两次(或更多)。它第一次看到它时一次,然后每次实例化模板。在第一次解析期间无法检测到所有错误:编译器在知道 T 之前无法知道 adder 没有默认构造函数。但它可以清楚地看到 adder 项定义了一个变量与参数同名,与 T 无关,因此它在解析模板时会发出错误,然后在尝试实例化它时再次发出错误。
    • 这很好。但我想知道标准中的部分,根据该部分adder&lt;T&gt;(item) 是一个名为 item 的变量的声明。
    • §6.8/1。基本上,如果一个标记序列可以被解释为一个声明或一个表达式语句,那么它就是一个声明。当然,如果您只想声明一个 adder,通常不会使用括号。但它们是合法的(并且是构造更复杂类型所必需的)。所以这是一个声明。
    【解决方案3】:

    目前我只能访问 C++0x 草案,所以我不能给你当前的章节和诗句,但我认为没有太大变化。 在 0x 中,它位于第 6.8 节 - 歧义解决:

    语法有歧义 涉及表达式语句和 声明:一个表达式语句 具有函数式显式类型 转换(5.2.3)作为它的最左边 子表达式可能无法区分 从第一个声明中 声明符以 (. 在那些 在这种情况下,该语句是一个声明。

    [...]

    T(a); // declaration
    

    即声明一个名为“a”的类型为 T 的变量。

    如果您的adder&lt;T&gt;(item) 定义了一个临时(未命名)对象,它将是一个表达式语句,但如果某些内容可以解析为声明语句或表达式语句,C++ 会将其解析为声明语句。

    [...] 解决方案是考虑任何 可能是一个构造 声明一个声明。 (8.2)

    换句话说,它是每个人亲爱的老朋友,最令人烦恼的 Parse 的表亲。

    更新: 我查看了 C++03 中的歧义解析,这些段落是相同的。

    【讨论】:

      【解决方案4】:

      “遮蔽”表示两个对象具有相同的名称,语言在这一点上允许这样做,但可能不是有意的。

      【讨论】:

      • 错了。标准第 3.3.2 节:“参数名称不得在函数定义的最外层块中或与函数尝试块关联的任何处理程序的最外层块中重新声明。”
      • 我也希望编译器实现该标准。 :)
      猜你喜欢
      • 2018-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-18
      • 2014-03-15
      • 2015-04-19
      • 1970-01-01
      相关资源
      最近更新 更多