3

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

这是代码:

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 <T> item'的声明遮蔽了参数
prog.cpp:在函数'void initializer(const T&)[with T = char [21]]':
prog.cpp:10: 从这里实例化
prog.cpp:6: 错误: 'adder<char [21]> item' 的声明遮蔽了参数
prog.cpp:6: 错误: 否调用 'adder<char [21]>::adder()'</strong>
prog.cpp:3 的匹配函数:注意:候选者是:adder<T>::adder(const T&) [with T = char [21]]
prog.cpp:3: 注意: adder<char [21]>::adder(const adder<char [21]>&)


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

错误:'<strong>adder<T> item ' 的声明遮蔽了参数
错误:'adder<char [21]> item ' 的声明遮蔽了参数

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

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

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


另一个有趣的错误是:

错误:没有匹配函数调用'adder<char [21]>::adder()'</p>

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


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

4

4 回答 4

4

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

因为编译器认为您使用名称 item 声明局部变量。

http://codepad.org/YBPKCvmm

于 2011-03-14T11:17:30.463 回答
3

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

在涉及表达式语句和声明的语法中存在歧义:将函数样式显式类型转换 (5.2.3) 作为其最左侧子表达式的表达式语句与第一个声明符以 (.在这些情况下,声明就是声明。

[...]

T(a); // declaration

也就是说,声明一个名为“a”的类型为 T 的变量。

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

[...] 决议是将任何可能是声明的结构视为声明。(8.2)

换句话说,它是大家亲爱的老朋友,最烦人的 Parse 的表亲。

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

于 2011-03-14T15:24:52.887 回答
3

理解正在发生的事情的关键是要意识到: adder(item); 是一个名为 item 并具有类型 adder 的局部变量的定义;括号是多余的,但完全允许。如果要调用构造函数,则必须以某种无法解释为数据定义的方式编写它来消除歧义,例如: adder((item)); (我不确定这可能有什么用。它构造了一个 adder 的临时对象,然后在表达式的末尾销毁它。)

一旦语句被理解为数据声明,实际的错误消息应该是清楚的(er):函数参数被视为在函数的顶级块中定义,因此 adder(item) 是重复的(并且是矛盾的)定义,并且 adder 没有默认构造函数,因此您不能在不提供参数的情况下定义它的实例。

于 2011-03-14T11:23:52.933 回答
1

“阴影”意味着两个对象具有相同的名称,语言在这一点上允许,但可能不是有意的。

于 2011-03-14T11:18:12.193 回答