Odd Template Compile Error

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!?!?!?
}

This is freaky because even Line 67 works with a pointer inside a vector!

Will have to experiment a little.
Weird indeed. I replaced line 58 with
1
2
B b( vi );
Z<B> z( b );
and it works fine..
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...

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..
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
I found that Z<B> z( (B( vi )) ) also worked
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?
wtf - gcc really thinks Z<B> z( (B( vi )) ) is different from Z<B> z( B( vi ) )

I am confused
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
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
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.