3

Today, I came across two error messages which I never seen before. It's completely new to me.

Here is the code:

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");
}

On compiling, GCC gives these errors:

prog.cpp: In function ‘void initializer(const T&)’:
prog.cpp:6: error: declaration of ‘adder<T> item’ shadows a parameter
prog.cpp: In function ‘void initializer(const T&) [with T = char [21]]’:
prog.cpp:10: instantiated from here
prog.cpp:6: error: declaration of ‘adder<char [21]> item’ shadows a parameter
prog.cpp:6: error: no matching function for call to ‘adder<char [21]>::adder()’
prog.cpp:3: note: candidates are: adder<T>::adder(const T&) [with T = char [21]]
prog.cpp:3: note: adder<char [21]>::adder(const adder<char [21]>&)


See the bold text. One error is shown twice, which is this

error: declaration of ‘adder<T> item’ shadows a parameter
error: declaration of ‘adder<char [21]> item’ shadows a parameter

What does it mean? Why does it show twice with different template arguments? First one with T, second one with char [21]?

EDIT: does adder<T>(item) declare variable with name item? But that is not what I intended. I think it should create a temporary object passing item as argument to the constructor.

I would like to know the section from the Standard which deals with this issue!


Other interesting error is this:

error: no matching function for call to ‘adder<char [21]>::adder()’

Which indicates that the compiler is looking for default constructor? But I'm wondering why is the compiler looking for it when in fact my code doesn't use it at line 6?


Code at ideone : http://www.ideone.com/jrdLL

Nawaz
  • 353,942
  • 115
  • 666
  • 851

4 Answers4

4

Which indicates that the compiler is looking for default constructor? But I'm wondering why is the compiler looking for it when in fact my code doesn't use it at line 6?

Because compiler think that you declare local variable with name item.

http://codepad.org/YBPKCvmm

NameemaN
  • 65
  • 1
  • 6
3

The key to understanding what is happening is to realize that: adder(item); is a definition of a local variable named item and having type adder; the parentheses are superfluous, but perfectly permissable. If you want to call the constructor, you'll have to disambiguate, by writing it in some way that cannot be interpreted as a data definition, say: adder((item)); (I'm not sure what use this may be. It constructs a temporary object of adder, then destructs it at the end of the expression.)

The actual error messages should be clear(er) once the statement is understood as a data declaration: function parameters are treated as if they were defined in the top level block of the function, so adder(item) is a duplicate (and contradictory) definition, and adder doesn't have a default constructor, so you can't define an instance of it without providing arguments.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 1
    Re the fact that one error appears twice: the compiler parses a template definition twice (or more). Once when it first sees it, and then each time it instantiates the template. Not all errors can be detected during the first parse: the compiler has no way of knowing that adder doesn't have a default constructor until it knows T. But it can clearly see that adder item defines a variable with the same name as the parameter, regardless of T, so it issues an error when it parses the template, and then again when it tries to instantiate it. – James Kanze Mar 14 '11 at 11:33
  • This is good. But I would like to know the section from the Standard according to which `adder(item)` is declaration of a variable with name *item*. – Nawaz Mar 14 '11 at 11:41
  • 1
    §6.8/1. Basically, if a sequence of tokens can be interpreted as a declaration or an expression-statement, it is a declaration. Naturally, you wouldn't normally use the parentheses if you wanted to just declare an adder. But they're legal (and necessary to construct more complex types). So it's a declaration. – James Kanze Mar 15 '11 at 19:14
3

I only have access to the C++0x draft at the moment, so I can't give you the current chapter and verse, but I don't think much has changed. In 0x it's in section 6.8 - Ambiguity Resolution:

There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.

[...]

T(a); // declaration

That is, a declaration of a variable named "a" of type T.

If your adder<T>(item) were to define a temporary (un-named) object, it would be an expression-statement, but if something can be parsed as either a declaration-statement or an expression-statement, C++ parses it as a declaration-statement.

[...] the resolution is to consider any construct that could possibly be a declaration a declaration. (8.2)

In other words, it's a cousin to everyone's dear old friend, the Most Vexing Parse.

Update: I looked at ambiguity resolution in C++03, and those passages are identical.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
1

"shadowing" means that two objects have the same name, which the language allows at this point, but might not be intended.

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • That's wrong. §3.3.2 of the standard: "A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block." – James Kanze Mar 14 '11 at 11:29
  • I, too, would prefer if compilers implemented the standard. :) – Simon Richter Mar 14 '11 at 12:40