Link to home
Start Free TrialLog in
Avatar of mitrakis
mitrakisFlag for Germany

asked on

tricky Q = strange compiler error ?

Hi there,

I have the following phenomenon (at least it's strange for me):
Why does the compiler indicate an error regarding the first method an why there's no error reported regarding the second method ?

//*****************************1st method
class A
{public:
   virtual const int f() const;
};

class B : public A
{public:
   virtual const int f() const
   {
      int(A::f());               // compiler error: 'A::f' : unable to resolve function overload
      const int(A::f());    // compiler error: 'A::f' : unable to resolve function overload
   }    
};

//*****************************2nd method
void main()
{
   A a;
   B b;
   int(a.f());      // no compiler error reported
   int(b.f());      // no compiler error reported
   int(b.A::f());  // no compiler error reported
   int(b.B::f());  // no compiler error reported
}

Any hints would be greatly appreciated !

Cheers
-Stavi-
Avatar of nietod
nietod

Did you try making the return value an int, not a const int?
That isn't it.    The fix is to name the integers, i.e.

    int i1(A::f())

works fine.

The question is why....  I'll let you know.   maybe.
I have no idea what is happening there.   I'm not sure if it is a VC quirk or the actuall correct behavior.   My thought was that

  int(A::f());      

could be interpretted as something other than the declaration of an initialized int.   But if so, I can't figure out what.   Note that if f() takes parameters, the problem also goes away..      That seems to make it a little suspicious to me--like it is a compiler error.

Also note, that this can happen in an unrelated member function in B.  i.e. in a function like B::X()
Avatar of mitrakis

ASKER

Thanks for feedback nietod !

I found out that *only* the following works fine *within* the method:
int(this->A::f());

whereas *outside* the method the following can be definded also:
int(A::f());

That means I had to change the above code as follows:

class B : public A
{public:
   virtual const int f() const
   {
      int(A::f());
      const int(A::f());

      int(this->A::f());       // works fine now !

      return 0;
   }    
};


But I have no (good) idea why it has to be this way :-))
Avatar of ambience
interesting .....

first the easy thing

>> int(a.f());      // no compiler error reported

creates a unnamed int variable that is initialized with returned value from a.f() and destroys it immediately. Its just like a constructor for primitive int type, which is valid in C++.

>>     int(A::f());              

this however is interesting, as different compilers have different opinion on that

VC: compiler error: 'A::f' : unable to resolve function overload
GCC: cannot declare member function `A::f' within `B'

in fact it appears that both think A::f is being declared inside B.

try this
const int(A::f() const);              

strangely enough VC doesnt complain about that, but even stranger is the fact that no call to A::f() is made and this statement is treated as a declaration inside B.

GCC however still complains.

Looks like i have to check what the standard has to say about that.
>> GCC: cannot declare member function `A::f' within `B'
I was tryign to interpret the statemetn as a declaration for a function, but I couldn't.  I still can't.  But apparently I am missing something, because GCC can.   i.e. somehow it looks like a function declaration.  If you add the parameters to f, or if you add a name to the int, it no longer looks like a function definition.


AH I got it now.  Thanks to ambience.   Those parentheseis can be ignored   Se what happens is that

int (A::f());    

is identical to

int A::f();    

try it, you can declare a funcion like

int (F(int i));

instead of

int F(int i);


So remove those ( for the intializer and you have

int A::f();

this looks like a declaration for a function.  

ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>  the overload problem that VC complains about is the missing "const" at the end of your declaration.

I am pretty much sure he didn't intend classify it as a declaration. Its only treated so by the compiler.

>> in fact it appears that both think A::f is being declared inside B.

* rather inside B::f() *

What is strange is that it is inside B::f(), and is it viable to declare a member function inside another member function ?? (only if it is valid somehow). I certainly dont see any reason such a declaration make any sense, and if not why wouldn't the compiler differentiate it from an ordinary declaration.

virtual const int f() const
{
     int(A::f());  // If a declaration here is not allowed
                   // and i think it shouldn't be
                   // this should be treated differently
     .....    
}    

Although GCC complains here but it doesn't bother to treat it the way the programmer has wanted it to, and VC doesn't even complain.

So this leads me to the question, is VC doing the right thing or GCC ?
>> I am pretty much sure he didn't intend classify it as a
>> declaration. Its only treated so by the compiler.
I'm sure.   But it is a declaration--even if no human would read it as such..  I have a lengthy descussion in my book  about the fact that unlike humans compiler's don't ever "know what we meant".  

>> What is strange is that it is inside B::f(), and is it viable to declare a
>> member function inside another member function
You can declare it, but not define it.   this is useful for forward declarations of functions that are defined later and for "using declarations" of functions from other namesaces when you want these declarations confined to the scope of the function.

>> So this leads me to the question, is VC doing the right thing or GCC ?
According to the standard if a program is ill formed, the compiler must not sucessfully compile it.   Both do this, bot are doing the right thing   It is not uncommon in C++ to encounter syntax errors that are ambiguous.  The compiler can't tall what is intended, so it different compilers may report the error in very different ways.   (This is one of the worst things about the C/C++ language.  syntax errors are much much harder to comprehend than in most other languages.  And typoes and mistakes by the programmer are more likely to be compiled succesfully, but operate not as intended, more than most other languages)
Well, the answer is way easier than any of you guessed:

Why isn't method 1 compiling? Because f is defined as a virtual function, thus it needs some sort of v-table to be resolved. As we all know, a class definition does *NOT* produce code/data unless an actual object of that class is instantiated. With that said, how is a compiler to resolve A::f()? It simply cannot since no object has been created and thus there is no v-table to be accessed to look up the address of f.
But why do the same lines of code work in a different context? Because in method 2 they are called, AFTER one of each classes has been instantiated.
>> Because f is defined as a virtual function, thus it needs some sort of v-table to be resolved

I seriously doubt the validity of such comment.

try this and you'll know

void B::f()
{
    A::f();
}
ambience,
   if you want to back your point with an example, that's perfectly ok. In that case, however, make it complete enough so that one can follow. If you don't put those 4 lines into a context you're invalidating them as a basis for discussion.
>> As we all know, a class definition does *NOT*
>> produce code/data unless an actual
>> object of that class is instantiated.
I don't know that!   The C++ standard has nothing to say about that.   However practical considerations do and most compilers will be unable to work that way.   (consider some counter examples, derived classes when there are no base classes.  (The base  classes might even appear in a seprately compiled translation unit.  the resulting object code must contain the class's compiled code and static data.))

>> how is a compiler to resolve A::f()? It simply
>> cannot since no object has been created and
>> thus there is no v-table to be accessed to look
>> up the address of f.
This "problem" occurs without virtual functions.   It has nothing to do with a v-table or anything of the sort.

>> Because in method 2 they are called,
>> AFTER one of each classes has been instantiated.
Well consider

class A
{
   public:
   virtual const int f() const;
};

class B : public A
{
   public:
   virtual const int f() const
   {
      A AnA;   // Add these
      B AB;

      int(A::f());               // compiler error: 'A::f' : unable to resolve function overload
      const int(A::f());    // compiler error: 'A::f' : unable to resolve function overload
}    

You should see no difference.  (I don't have time to test, but I would be shocked if there was a change.)



mitrakis,  we need to hear from you.  
This may seem simple, and it may be just an oversite in the posting of the code.  There is no function definition for A::f and it is not declared as a pure virtual function. try one of these:
class A
{public:
  virtual const int f() const = 0;
};

class B : public A
{public:
  virtual const int f() const
  {
     int(A::f());               // compiler error: 'A::f' : unable to resolve function overload
     const int(A::f());    // compiler error: 'A::f' : unable to resolve function overload
  }    
};

or

class A
{public:
  virtual const int f() const{};
};

class B : public A
{public:
  virtual const int f() const
  {
     int(A::f());               // compiler error: 'A::f' : unable to resolve function overload
     const int(A::f());    // compiler error: 'A::f' : unable to resolve function overload
  }    
};
I don't understand that.  What is the point you are making?  
back again...

First aof all I'd like to thank you all for the helpful comments and also for the various code examples.
What I understood is that the compiler behaves quite different when trying to understand what the programmer wanted to achieve by using certain statements...correct me if I'm wrong...but that will be the problem for the next couple of milleniums ;)

I really would like to award nietod and ambience the points since their comments pointed me to the right direction.
I'm sure now, I didn't make an error in my code. Just had to change my dialect so the compiler can understand easily what my intention was ;)

I suggest to give points to nietod and to open a new Q to be answered by ambience.
Give me a feedback if this is ok for you.

Best regards
-Stavi-

P.S.:
I'm sure this topic can be discussed another hundred years concerning the ability or inability of good or bad compilers...thanks a lot anyway.
That is not quite true. A compiler doesn't want to understand what the programmer wanted to achieve - neither does it have to to produce code. The constructs you were handing to the compiler didn't resemble what you meant to say to begin with.

As for the next couple of milleniums (millenia? anyone?) compilers will evolve, surely. Not in the way that they will UNDERSTAND what the programmer meant but in complying with the standard. A compiler's job is a lot like blindly translating a document into a different language using a dictionary. There is very little interpretation involved. In fact, I only came across one single instance in my life when a line of c++-code was truely ambiguous and could have been - legally - interpreted in two different ways by a standard conforming compiler. If the compiler did care about my intentions it would have compiled. But a compiler simply doesn't care.

The right direction for you, though, would be to UNDERSTAND the compiler more thoroughly as well as the language it takes as an input. In c++ there is no such thing as dialect - at least not as far as the standard goes.

I hope this made things a bit clearer for you.
>> What I understood is that the compiler behaves quite different when
>> trying to understand what the programmer wanted to achieve by
>> using certain statements.
It behaves differently only in how it interprets a mistake, not in whethor or not it is a mistake.  that is understandable, the compiler is not psychic , or even smart, so it has to try to guess at what you entended as best as possible.   So for example if it sees

if (X =! Y)

One compiler  might guess that the user placed the two symbols in the wrong order and really meant (X != Y) while another compiler might guess that the user meant to place a space before the ! and really mean (X = !Y).  But compilers are right that the code is wrong, but they may not know what was really intended.

>> The constructs you were handing to the compiler didn't resemble what
>> you meant to say to begin with.
I'm not sure about that.   anonomous objects are a very useful feature of C/C++.  But I would recommend you restrict their use to within expressions, i.e.  if you want to pass point objects to a function you would do something like

   Line(Point(0,0),Point(100,100));

but there is little reaason to declare anonomous objects, like

   Point(0,0);

such an object cannot ever be used for anything.  The only "useful" result from this can come out of its constructor and destructor.  Now sometimes that does happen.  i.e. some classes might start an action in the constructor and complete it in the destructor.  If you have a class like that you can still use it, but just don't make it anonomous, give it a name like

   LockFileObject ALock();

(millenia? anyone?)
yes, millenia.   (And by the way all you programmers out there "data" is plural.  "datum" is the signular!)

>> Not in the way that they will UNDERSTAND what the
>> programmer meant but in complying with the standard
Do you think a millenium is enough to comply with the standard?  :-)

>>  I only came across one single instance in my life when a line of
>> c++-code was truely ambiguous and could have been - legally -
>> interpreted in two different ways by a standard conforming compiler.
Ther are actually about a dozen of these problems known.

>>  In c++ there is no such thing as dialect - at least not as
>> far as the standard goes.
Well as far as the sandard goes, yes there is only one C++ (its few known problems aside).  Unfortunately, there are no fully compliant C++ compilers in the world and there probably will never be.  Thus each compiler "understands" a slightly different language. Many are fairly similar, but some are quit different.   VC is probalby one of the least compliant of the major compilers, so if that's what you are using, you might need to be prepared for a little hardship.  Fortunately MS is now committed to make it fully compliant (which is impossible).
> Fortunately MS is now committed to make it fully
> compliant (which is impossible).

How can you say that? Does the language have built-in contradictions? If not then a compiler can be made fully compliant - at least that's what the theory of computation demands.
>> How can you say that?
I am a realist.  A compiler that is 100% compliant is certanly theoreticaly possible, but practically impossible.  The language is just too complex.  There will always be bugs, at least until we can someday appply programatic solutions to generating the perfect compiler, but that is not even possible (much less realstic) until the language is perfect, and there are flaws with it too.   Even if there was programmers that could write the perfect compiler, it would probably still have flaws due to his/her missunderstanding of the standard.    You need to find someone that understands the standard perfectly and can write a program with no flaws.  You'd have better odds looking for 1 honest man.  (he's the one that says he can't program perfectly....)

Points have been reduced for split.  Now you can accept an experts comment as an answer.  After that, make another question in this topic are for the other expert.  Label the question, "Question for (Expert Name)and post the desired points.

Computer101
E-E moderator
Thanks a lot for your input on this issue guys.

Regards
-Stavi-