Odd Template Compile Error

May 7, 2011 at 7:24pm
3:30AM so brain is getting mushy - I need a sanity check with an odd compile error in gcc with this code below.

If Line 70 is commented out, rest of the code compiles and runs fine.
Uncommented, gcc spits out:

test.cpp:70: error: request for member 'getQuantity' in 'z', which is of non-class type 'Z<B> ()(B)'


Any idea what I am doing wrong?

test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;

class P {
  public:
    virtual int getQuantity() const = 0;
};

// ----------------------------------------------------------------------

class A : public P {
  public:
    virtual int getQuantity() const { return m_i; }
    A( int i ) : m_i( i ) { }
  private:
    int m_i;
};

class B : public P {
  public:
    virtual int getQuantity() const {
      return accumulate( m_v.begin(), m_v.end(), 0 );
    }
    B( const vector<int>& v ) : m_v( v ) { }
  private:
    vector<int> m_v;
};

// ----------------------------------------------------------------------

template<class HasQuantity>
class Y : public HasQuantity
{
  public:
    Y( const HasQuantity& x ) : HasQuantity( x ) { }
};

template<class HasQuantity>
class Z : public HasQuantity
{ 
  public:
    Z( const HasQuantity& x ) : HasQuantity( x ) { }
};

// ----------------------------------------------------------------------

main()
{
  vector< int > vi;
  vi.push_back( 1 );
  vi.push_back( 2 );
  vi.push_back( 3 );

  Y<A> y( A( 5  ));
  Z<B> z( B( vi ));

  vector< A* > u;
  u.push_back( new Y<A>( A( 9 )));

  vector< B* > v;
  v.push_back( new Z<B>( B( vi )));

  cerr << u[0]->getQuantity() << endl; // OK
  cerr << v[0]->getQuantity() << endl; // OK

  cerr << y.getQuantity() << endl; // OK!
  cerr << z.getQuantity() << endl; // but... ...COMPILE ERROR!?!?!?
}

May 7, 2011 at 7:42pm
This is freaky because even Line 67 works with a pointer inside a vector!

Will have to experiment a little.
May 7, 2011 at 7:50pm
Weird indeed. I replaced line 58 with
1
2
B b( vi );
Z<B> z( b );
and it works fine..
May 7, 2011 at 7:58pm
ty, hamsterman! that's a great help - I think it has to do with my understanding of passing in B( vi ) into the constructor.

Oddly enough, Line 64 works, though.

I want to dig some more so I can understand why this is happening...

May 7, 2011 at 8:04pm
Apparently Z<B> z = Z<B>( B( vi )); works too.

It's sad. You think you know the language and then you find this..

By the way, why is your main so C ? I don't think that should compile..
May 7, 2011 at 8:16pm
That's just laziness when doing simple tests.

What's even stranger now, is that even when I compile with -O0, that variable doesn't show up when I try "info locals", but the others do! very spooky

It's not just sad, it's scary - at least the compiler is complaining - always better at compile-time than at run-time... ...going to look some more.
Last edited on May 7, 2011 at 8:17pm
May 7, 2011 at 8:17pm
I found that Z<B> z( (B( vi )) ) also worked
May 7, 2011 at 8:23pm
now that's odd!

I wonder if it has something to do with lifetime of temporaries - usually, my very last guess would be that it's a compiler bug (I've been proven wrong too many times).

I don't have a Windows box here - could someone do a sanity check with some other environment/compiler and make sure we haven't gone crazy?
May 7, 2011 at 8:25pm
wtf - gcc really thinks Z<B> z( (B( vi )) ) is different from Z<B> z( B( vi ) )

I am confused
May 7, 2011 at 8:27pm
I'm using VC++.

typeid.name() gave me "class Z<class B> __cdecl(class B)"
I guess it could have been predicted from your error message that the compiler considers this to be a function declaration...

edit:
Also, if I change line 57 to
1
2
int i = 5;
Y<A> y( A( i  ));
I get the same error.

edit:
Apparently it's ok to surround argument names with parenthesis when declaring a function..
Last edited on May 7, 2011 at 8:32pm
May 7, 2011 at 8:33pm
that's a useful insight - and makes some sense if the parser thought it was a function declaration

but why do you think?

1
2
Z<B> z_ok( ( B( vi ))); // is an instance
Z<B> z_bad( B( vi ));   // is a function declaration? 


there must be something in the C++ specifications that says so because VC++ and gcc seems to agree here (thx for the sanity check, hamsterman)

(was just thinking that this would be a very nasty question for a job interview)

edit:
I wonder if the extra parens gives the compiler a chance to create a temporary before the parser decides whether the line is really a function declaration or an object
Last edited on May 7, 2011 at 8:49pm
May 7, 2011 at 9:04pm
Thank you, hamsterman, guestgulkan

I'm going to mark this one as solved.

As I understand it, the funky cases appear to be:

1
2
3
Z<B> z_ok( ( B( vi ))); // is an instance
Z<B> z_bad( B( vi ));   // is a function declaration
Z<B> z_alsobad( B );   // is a function declaration 


All other examples in this thread thus far are unambiguously instances.
Line 1 is a small surprise, until you accept that the extra parens is creating a temporary.
Line 2 is a surprise due to human mis-interpretation - there is probably a C++ spec out there which says this is the way it should be
Line 3 is what we expect

Topic archived. No new replies allowed.