Click here to Skip to main content
15,884,473 members
Please Sign up or sign in to vote.
5.00/5 (3 votes)
See more:
I had no success finding help on the web, but I also have some trouble to concisely define my problem, so I'll start with the code:

C++
const cHalfEdge* cHalfEdge::prev() const
{
   const cHalfEdge* result = nullptr;
   if (next_ != nullptr) {
      const cHalfEdge* current = this;
      while (current->next_ != nullptr && current->next_ != this) {
         current = current->next_;
      }
      if (current->next_ == this)
         result = current;
   }
   return result;
}

cHalfEdge* cHalfEdge::prev()
{
   const cHalfEdge* result = (const cHalfEdge*)(this)->prev();
   return const_cast<cHalfEdge*>(result);
}

As you can see, I have two overloaded versions of the same function, that differ only in their respective const qualifier. I deliberately made two functions to ensure const-correctness. Since the implementation is the same however, I want it to be in only one place.

Now the problem arises that I cannot easily call one version from the other. In the code above, I did a small hack to force the call of the other version, and even though I haven't even run the program yet, I am sure that it works. Still, the compiler (VC10.0) issues a warning, claiming that this function will cause an endless recursion.

I realize there are other possible solutions, e. g. to move the implementation to a function with a different name. But that is not the problem I wish to discuss.

I always try to avoid type casts, and that first one is particularly ugly. I wondered if it is really necessary - And that is where my question arises:

Is it possible to specifically call the const version of an overloaded function without casting the object I'm calling it on to const?

Edit:
After improving the wording of my question and trying another search, I've found a similar discussion here:
http://stackoverflow.com/questions/5620071/how-do-i-call-overloaded-member-function-with-cv-qualifier[^]
Looks like it is indeed necessary to const-cast the object (this, in this case). Pity, I would have hoped for a more elgant solution.
Posted
Updated 6-Sep-13 2:06am
v4
Comments
Jochen Arndt 6-Sep-13 6:40am    
An interesting question: +5

It will not work. Warning C4717 indicates that the compiler will not call the const version but recursively calls the non const version.
Stefan_Lang 6-Sep-13 7:01am    
Yep, nv3 got it - it's a precedence problem.
phil.o 6-Sep-13 6:55am    
Voted 5 also, what a pleasure to see a well-formed question exposing clear problematic!

You can skip the cast to const as assigning something to a const member does nothing (usually) to the source object.

So you could replace
C++
cHalfEdge* cHalfEdge::prev()
{
   const cHalfEdge* result = (const cHalfEdge*)(this)->prev();
   return const_cast<cHalfEdge*>(result);
}

with
C++
cHalfEdge* cHalfEdge::prev()
{
   const cHalfEdge* const_this = this;
   return const_cast<cHalfEdge*>(const_this->prev());
}


That removes the explict (const cHalfEdge*) cast.

You will always have to cast away the const on the result though.

Hope this helps,
Fredrik
 
Share this answer
 
Comments
Stefan_Lang 6-Sep-13 8:09am    
Thanks for this suggestion. It is less than I hoped for, but apparently there's no way around somehow converting this to const.

I'll accept this as solution as it suggests the best readable (i. e. least confusing) variant.
Fredrik Bornander 6-Sep-13 8:14am    
Cool, glad I could "help" :)
I realize it's not perfect but I don't think this is something you really want to do anyway.
I assuming that since you asked a fairly complex question you're aware that casting away const on your own return value means you might as well remove the const from the return type all together.
Philippe Mori 6-Sep-13 19:08pm    
This is a very good solution. The only better alternative is to have a private third function with a different name if it is possible to implement the function cHalfEdge * cHalfEdge::prev_implementation() const without doing any cast (but you said you want something else).
Stefan_Lang 9-Sep-13 3:28am    
I've thought of that but I prefer my const correctness to be deep, i. e. 'inherited' through pointer members. That is why I deliberately chose my const function to return a pointer to const.

The locally implemented function wouldn't know if it's safe to silently 'cast away deep-constness'. The suggested solution does.

Of course that all is beside the point of my actual question, the answer to which is "No" (unfortunately). As I said, I accepted this solution because it's the best readable workaround to (in)directly call a const overload.
Stefan_Lang 9-Sep-13 10:23am    
P.S.: I just realized there is one tricky part for this form of implementation: if the edge is closed, i. e. its end point coincides with its starting point, then the correct result would be this, which is const. However, I then realized that, rather than return const_cast<cHalfEdge*>(this), I could simply return next_, obviating the need for a cast ;-)
I think you are stumbling over an operator issue. What you intended to do was:
C++
const cHalfEdge* result = ((const cHalfEdge*)this)->prev();


[EDIT]
I don't think that there is a direct way to specify that you want to call the const overload of the function, except making the cast a little nicer:
C++
const cHalfEdge* result = const_cast<const cHalfEdge*>(this)->prev();
 
Share this answer
 
v2
Comments
Stefan_Lang 6-Sep-13 7:01am    
Good catch, I hadn't checked precedence rules properly.

Still, my question remains if there is a way to call the const version without the crutch of a cast.
nv3 6-Sep-13 7:33am    
As far as I know there is no way to influence the resolution of the overloaded function. And the resolution rule with regard to constness always prefers the overload that has the same constness as the object it is called upon. But see my [EDIT] above.

After a long time another interesting question!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900