今天,我遇到了两条我从未见过的错误消息。这对我来说是全新的。
以下是代码:
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&amp;)'中:
prog.cpp:6:错误:'adder&lt; T&gt;的声明item'遮蔽参数
prog.cpp:在函数'void initializer(const T&amp;)[with T = char [21]]':
prog.cpp:10:从这里实例化 prog.cpp:6:错误:'adder&lt; char [21]&gt;的声明item'遮蔽参数
prog.cpp:6:错误:没有匹配函数来调用'adder&lt; char [21]&gt; :: adder()'
prog.cpp:3:注意:候选者是:adder&lt; T&gt; :: adder(const T&amp;)[with T = char [21]]
prog.cpp:3:注意:adder&lt; char [21]&gt; :: adder(const adder&lt; char [21]&gt;&amp;)
请参阅粗体文字。一个错误显示为两次,这是
错误:声明'加法器&lt; T&gt; item '阴影参数
错误:声明'加法器&lt; char [21]&gt; item '遮蔽参数
这是什么意思?为什么用不同的模板参数显示两次?第一个是T
,第二个是char [21]
?
编辑:adder<T>(item)
是否使用名称 item 声明变量?但这不是我的意图。我认为它应该创建一个临时对象,将 item 作为参数传递给构造函数。
我想知道标准中涉及此问题的部分!
其他有趣的错误是:
错误:没有匹配函数来调用'adder&lt; char [21]&gt; :: adder()'
这表明编译器正在寻找默认构造函数?但是我想知道为什么编译器在寻找它时实际上我的代码不使用它在第6行?
ideone上的代码:http://www.ideone.com/jrdLL
答案 0 :(得分:4)
这表明编译器正在寻找默认构造函数?但是我想知道为什么编译器在寻找它时实际上我的代码在第6行没有使用它?
因为编译器认为你用名称项声明了局部变量。
答案 1 :(得分:3)
理解正在发生的事情的关键是要意识到: 加法器(项目); 是名为item且具有类型的局部变量的定义 加法器;括号是多余的,但完美无缺 permissable。如果你想调用构造函数,你就可以了 通过以某种不可能的方式写出来消除歧义 解释为数据定义,说: 加法器((项目)); (我不确定这可能是什么用。它构造了一个临时的 加法器的对象,然后在结束时破坏它 表达。)
一旦声明,实际的错误消息应该是明确的(呃) 被理解为数据声明:函数参数是 对待它们就好像它们被定义在顶层的块中一样 函数,所以加法器(项)是重复的(和矛盾的) 定义,而adder没有默认构造函数,所以 如果不提供参数,就无法定义它的实例。
答案 2 :(得分:3)
我目前只能访问C ++ 0x草案,所以我不能给你当前的章节和经文,但我认为没有太多改变。 在0x中,它在6.8节 - 模糊度解析:
中语法含糊不清 涉及表达式陈述和 声明:表达式语句 使用函数样式的显式类型 转换(5.2.3)为最左边 子表达式可以无法区分 从第一个声明 声明符以a开头(。在那些 这种说法是一种声明。
[...]
T(a); // declaration
即,声明类型为T的变量“a”
如果您的adder<T>(item)
要定义一个临时(未命名)对象,那么它将是一个表达式语句,但是如果可以将某些内容解析为声明语句或表达式语句,则C ++会解析它作为宣言声明。
[...]决议是考虑任何问题 构造可能是一个 声明声明。 (8.2)
换句话说,它是每个亲爱的老朋友,最烦恼的解析的堂兄。
更新的 我查看了C ++ 03中的歧义解决方案,这些段落是相同的。
答案 3 :(得分:1)
“阴影”表示两个对象具有相同的名称,此时语言允许这样做,但可能不是这样。