Constructors taking single temporary objects mistaken for functionpointers?

J

jason.cipriani

The following program fails to compile with what appears to be a
really strange error:

struct A {
};

struct B {
B (const A&);
void f();
};

int main () {
B b(A()); // pass temporary A to constructor.
b.f();
}

Comeau gives:

"ComeauTest.c", line 12: error: expression must have class type
b.f();

MSVC gives:

c:\temp\pqueue\pqueue.cpp(12) : error C2228: left of '.f' must have
class/struct/union

And "geordi", some weird C++ compiling IRC bot, gives:

error: request for member 'f' in 'b', which is of non-class type 'B ()
(A (*)())'

What the heck is going on here? I am able to make it compile by
putting the A() inside an extra set of parentheses:

int main () {
B b((A()));
b.f();
}

But I'm not sure why it's mistaking what I'm trying to do for a
function pointer declaration. I first ran into this error in the
seemingly reasonable program:

#include <queue>
int main () {
std::priority_queue<int> pq(less<int>());
pq.push(0);
}

Where I was attempting to pass a predicate function to the
constructor. Although the following fails with the same error:

#include <queue>
int main () {
std::priority_queue<int> pq();
pq.push(0);
}

In fact, any program of this form fails to compile:

struct A { void f(); };
int main () {
A a();
a.f();
}

And that completely boggles my mind for two reasons:

1. While empty parens for default constructor are not the usual
style, that seems like entirely reasonable code.
2. I'm no master, but I am completely confused as to how I've never
noticed this before, I feel like I've been programming long enough to
have run into it at least once.

Why are these programs not compiling? I mean, I understand that it
thinks I'm declaring function pointers for some reason, but it doesn't
make any sense to me why it would think that.

Thanks,
JC
 
R

Rolf Magnus

The following program fails to compile with what appears to be a
really strange error:

struct A {
};

struct B {
B (const A&);
void f();
};

int main () {
B b(A()); // pass temporary A to constructor.

There is neither a temporary, nor a constructor involved here. The above
declares a function named b, returning a B and taking a pointer to a
function returning an A as parameter.
What the heck is going on here? I am able to make it compile by
putting the A() inside an extra set of parentheses:

int main () {
B b((A()));
b.f();
}

But I'm not sure why it's mistaking what I'm trying to do for a
function pointer declaration.

Because that's how C++ works. If it looks like a function declaration, it is
a function declaration.
I first ran into this error in the
seemingly reasonable program:

#include <queue>
int main () {
std::priority_queue<int> pq(less<int>());
pq.push(0);
}

Where I was attempting to pass a predicate function to the
constructor. Although the following fails with the same error:

#include <queue>
int main () {
std::priority_queue<int> pq();
pq.push(0);
}

In fact, any program of this form fails to compile:

struct A { void f(); };
int main () {
A a();
a.f();
}

And that completely boggles my mind for two reasons:

1. While empty parens for default constructor are not the usual
style, that seems like entirely reasonable code.

Well, how would you write a declaration for a function named a, returning an
A? Would that not be:

A a();

? And if it would, how can the compiler know that you want something else
here?
Why are these programs not compiling? I mean, I understand that it
thinks I'm declaring function pointers for some reason, but it doesn't
make any sense to me why it would think that.

The reason is that it looks like a function declaration.
 
V

Vaclav Haisman

The following program fails to compile with what appears to be a
really strange error:

struct A {
};

struct B {
B (const A&);
void f();
};

int main () {
B b(A()); // pass temporary A to constructor.
b.f();
}

Comeau gives:

"ComeauTest.c", line 12: error: expression must have class type
b.f();

MSVC gives:

c:\temp\pqueue\pqueue.cpp(12) : error C2228: left of '.f' must have
class/struct/union

And "geordi", some weird C++ compiling IRC bot, gives:

error: request for member 'f' in 'b', which is of non-class type 'B ()
(A (*)())'

What the heck is going on here? I am able to make it compile by
putting the A() inside an extra set of parentheses:

int main () {
B b((A()));
b.f();
}

But I'm not sure why it's mistaking what I'm trying to do for a
function pointer declaration. I first ran into this error in the
seemingly reasonable program:

#include <queue>
int main () {
std::priority_queue<int> pq(less<int>());
pq.push(0);
}

Where I was attempting to pass a predicate function to the
constructor. Although the following fails with the same error:

#include <queue>
int main () {
std::priority_queue<int> pq();
pq.push(0);
}

In fact, any program of this form fails to compile:

struct A { void f(); };
int main () {
A a();
a.f();
}

And that completely boggles my mind for two reasons:

1. While empty parens for default constructor are not the usual
style, that seems like entirely reasonable code.
2. I'm no master, but I am completely confused as to how I've never
noticed this before, I feel like I've been programming long enough to
have run into it at least once.

Why are these programs not compiling? I mean, I understand that it
thinks I'm declaring function pointers for some reason, but it doesn't
make any sense to me why it would think that.
Basically, anything that looks like a function declaration _is_ function
declaration. Anything of the form <type> name (<type>); is function declaration.

Let's say we modify your code like this:

#include <iostream>

// Your A and B classes.

int main () {
B b((A())); // pass temporary A to constructor.
void foo (int ()); // the int() is actually int(*)()
foo (0);
b.f();
}

void foo (int(*)())
{
std::cout << "ahoy!" << std::endl;
}

The void foo (int ()); declaration does declare a function like your A b
(A()); would. If you compile the modified test case it will print "ahoy!". If
you remove the declaration inside main() then it will not compile at all.
 
J

jason.cipriani

There is neither a temporary, nor a constructor involved here. The above
declares a function named b, returning a B and taking a pointer to a
function returning an A as parameter.




Because that's how C++ works. If it looks like a function declaration, it is
a function declaration.











Well, how would you write a declaration for a function named a, returning an
A? Would that not be:

A a();

? And if it would, how can the compiler know that you want something else
here?


The reason is that it looks like a function declaration.


Thanks for clearing it up; I guess it caught me by surprise. It seems
a little ... almost sloppy ... of the grammar to make you add an extra
set of parentheses around a function parameter like that. I guess
anything of the form:

Type name(Type(), Type(), Type(), ...)

Would look like a function pointer. For example, I do this:

struct B {
B (int, int, int) { }
void f();
};

int main () {
B b(int(), int(), int());
b.f();
}

And I get the error, yet putting an extra set of parentheses around
any single one of those int()s (doesn't matter which) makes everything
OK again, e.g.:

B b(int(), (int()), int());
b.f();

It seems sloppy in the same way the nested template >> thing is
sloppy.

Of course, now that I know what's going on, it's easy to not make the
mistake again. Also, I guess I don't really have any idea of how to
make it less... strange. Still, it did catch me off guard and made me
raise an eyebrow a little.

Thanks,
Jason
 
J

jason.cipriani

(e-mail address removed) wrote, On 25.12.2008 9:44:






















Basically, anything that looks like a function declaration _is_ function
declaration. Anything of the form <type> name (<type>); is function declaration.

Let's say we modify your code like this:

#include <iostream>

// Your A and B classes.

int main () {
  B b((A())); // pass temporary A to constructor.
  void foo (int ()); // the int() is actually int(*)()
  foo (0);
  b.f();

}

void foo (int(*)())
{
  std::cout << "ahoy!" << std::endl;

}

The void foo (int ()); declaration does declare a function like your A b
(A()); would. If you compile the modified test case it will print "ahoy!".. If
 you remove the declaration inside main() then it will not compile at all.

Thanks, that was a good explanation.

Jason
 

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
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top