Completely misleading declaration

J

Juha Nieminen

Assume we have a piece of code like this:

#include <map>

struct A { ... };
struct Comp { bool operator()(const A&, const A&) const { ... } };

int main()
{
std::map<A, int, Comp> theMap(Comp());

A a;
theMap[a] = 5;
}

All is well, right? No. gcc gives this error:

error: no match for 'operator[]' in 'theMap[a]'

Inexperienced C++ programmers will be completely confused by this
error message.

Experienced C++ programmers may see what is the problem: What looks
like a map instantiation called 'theMap' actually isn't. It actually is
a function declaration. This even though we are seemingly creating a
(nameless) instance of Comp which we give to this map as parameter. How
can a function be declared with a parameter which is an instance of a
struct instead of being a parameter type?

It seems that we have a doubly-confusing declaration here. In fact, in
this case it doesn't seem to be an instantiation of Comp at all.
Instead, at least according to gcc, it declares a function pointer
type (!)

So, in all its glory, the line:

std::map<A, int, Comp> theMap(Comp());

declares a function named 'theMap' which returns an instance of
std::map<A, int, Comp> and which takes one parameter: A pointer to a
function taking no parameters and which returns an instance of Comp.

Could this become any more confusing?

A small change in that line completely changes its semantic meaning:

std::map<A, int, Comp> theMap((Comp()));

Now it does what it looks like it should do: It creates a map instance
called 'theMap' and gives its constructor an instance of Comp.

Anyways, my actual question is the following:

Is gcc behaving correctly here? Can you really declare a function
pointer type as "Comp()" instead of the more common "Comp (*)()"?
 
W

White Wolf

Juha Nieminen said:
Assume we have a piece of code like this:

#include <map>

struct A { ... };
struct Comp { bool operator()(const A&, const A&) const { ... } };

int main()
{
std::map<A, int, Comp> theMap(Comp());

A a;
theMap[a] = 5;
}

All is well, right? No. gcc gives this error:

error: no match for 'operator[]' in 'theMap[a]'

Inexperienced C++ programmers will be completely confused by this
error message. [SNIP]
Is gcc behaving correctly here? Can you really declare a function
pointer type as "Comp()" instead of the more common "Comp (*)()"?

Read Item 6 of Effective STL from Scott Meyers. Yes, this is a frustrating
C++ "feature". It is explained in depth in the book.

Attila
 
J

James Kanze

Juha said:
Assume we have a piece of code like this:
#include <map>
struct A { ... };
struct Comp { bool operator()(const A&, const A&) const { ... } };
int main()
{
std::map<A, int, Comp> theMap(Comp());
A a;
theMap[a] = 5;
}
All is well, right? No. gcc gives this error:
error: no match for 'operator[]' in 'theMap[a]'
Inexperienced C++ programmers will be completely confused by this
error message.

Even experienced C++ programmers might be confused with it.
Given the frequency of this error, a compiler can be more
explicit about it. (I seem to recall g++ also outputting
information about the types it was working with.)
Experienced C++ programmers may see what is the problem: What
looks like a map instantiation called 'theMap' actually isn't.
It actually is a function declaration. This even though we are
seemingly creating a (nameless) instance of Comp which we give
to this map as parameter. How can a function be declared with
a parameter which is an instance of a struct instead of being
a parameter type?

Because for historical reasons, C++ declaration syntax is
broken, and there's no easy way to fix it without breaking
existing code.
It seems that we have a doubly-confusing declaration here. In
fact, in this case it doesn't seem to be an instantiation of
Comp at all. Instead, at least according to gcc, it declares
a function pointer type (!)
So, in all its glory, the line:
std::map<A, int, Comp> theMap(Comp());
declares a function named 'theMap' which returns an instance
of std::map<A, int, Comp> and which takes one parameter: A
pointer to a function taking no parameters and which returns
an instance of Comp.
Could this become any more confusing?
A small change in that line completely changes its semantic
meaning:
std::map<A, int, Comp> theMap((Comp()));
Now it does what it looks like it should do: It creates a map
instance called 'theMap' and gives its constructor an instance
of Comp.
Anyways, my actual question is the following:
Is gcc behaving correctly here? Can you really declare a
function pointer type as "Comp()" instead of the more common
"Comp (*)()"?

Yep. You've just run into a case of the most embarassing parse.
I don't think anyone likes the current situation, but to date,
no one has been able to propose an acceptable alternative.
 
J

Jeff Schwab

Juha said:
Assume we have a piece of code like this:

#include <map>

struct A { ... };
struct Comp { bool operator()(const A&, const A&) const { ... } };

int main()
{
std::map<A, int, Comp> theMap(Comp());

A a;
theMap[a] = 5;
}

All is well, right? No. gcc gives this error:

error: no match for 'operator[]' in 'theMap[a]'

You're right: that error message is unacceptable, especially since this
is famous as probably the nastiest syntactic gotcha in the entire
language. Are you using GCC? A patch may be in order.
 
B

Barry

On 3ÔÂ19ÈÕ said:
Is gcc behaving correctly here? Can you really declare a function
pointer type as "Comp()" instead of the more common "Comp (*)()"?

A nit,
I think, the complier takes it as a "function type".
But there's "function -> pointer" conversion (4.3).
They are still different.

I saw some programmer declare pointer to function in way,
typedef void CallbackFunc(int);
CallbackFunc* pfn = someFunc;

which makes the declaration the way normal pointers do.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,176
Messages
2,570,947
Members
47,499
Latest member
DewittK739

Latest Threads

Top