468,738 Members | 2,676 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,738 developers. It's quick & easy.

an "optional const"

hello;-)

i frequently need the following construction:

ReturnParam Function()
{
/...do something.../
someType var = something;
/...do something.../
return something;
}

where may be 'const' or nothing. So, if the function is called as a
member function of a constant object, it needs exactly the same code
as its non-const sister, but with some additional 'const' somewhere in
the fuction.

To reduce code-doubling, it would be very nice to have some "optional
const", eg. something that the compiler automatically removes if the
fn is called on an non-const object and translates to 'const' if the
object is constant.

As i cant think of any possibility that this would break existing
code, and furthermore think it should be easy to implement.

So i'd like to know if someone sees any reason to not propose an
"optional const", and - just by the way ;-) - where i could to it...
Sep 15 '08 #1
6 2032
..rhavin grobert wrote:
hello;-)

i frequently need the following construction:

ReturnParam Function()
A 'const' in the return type does not matter. The difference, however,
is sometimes like this:

ReturnType Function() const

vs

ReturnType& Function()

Therefore, it's not "const" versus "non-const" in the return value type,
it's a "temporary object" versus "reference" or

ReturnType const& Function() const

vs

ReturnType & Function()

, i.e. the 'const' in the return type is not where you show it.
{
/...do something.../
someType var = something;
/...do something.../
return something;
}

where may be 'const' or nothing. So, if the function is called as a
member function of a constant object, it needs exactly the same code
as its non-const sister, but with some additional 'const' somewhere in
the fuction.

To reduce code-doubling, it would be very nice to have some "optional
const", eg. something that the compiler automatically removes if the
fn is called on an non-const object and translates to 'const' if the
object is constant.

As i cant think of any possibility that this would break existing
code, and furthermore think it should be easy to implement.

So i'd like to know if someone sees any reason to not propose an
"optional const", and - just by the way ;-) - where i could to it...
AFAIK, folks who are sure that the 'do something' parts in those two
functions do not differ at all, simply write a const version and in the
non-const version do the const_cast in and out:

ReturnType const& Function() const
{
/* do something */
}

ReturnType& Function()
{
return const_cast<ReturnType&>(
const_cast<ThisClass const&>(*this).Function()
);
}

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 15 '08 #2
On 15 Sep., 16:42, Victor Bazarov <v.Abaza...@comAcast.netwrote:
.rhavin grobert wrote:
hello;-)
i frequently need the following construction:
ReturnParam Function()

A 'const' in the return type does not matter. *The difference, however,
is sometimes like this:

* * *ReturnType Function() const

vs

* * *ReturnType& Function()

Therefore, it's not "const" versus "non-const" in the return value type,
it's a "temporary object" versus "reference" or

* * *ReturnType const& Function() const

vs

* * *ReturnType & Function()

, i.e. the 'const' in the return type is not where you show it.
{
* /...do something.../
* someType var = something;
* /...do something.../
* return something;
}
where may be 'const' or nothing. So, if the function is called as a
member function of a constant object, it needs exactly the same code
as its non-const sister, but with some additional 'const' somewhere in
the fuction.
To reduce code-doubling, it would be very nice to have some "optional
const", eg. something that the compiler automatically removes if the
fn is called on an non-const object and translates to 'const' if the
object is constant.
As i cant think of any possibility that this would break existing
code, and furthermore think it should be easy to implement.
So i'd like to know if someone sees any reason to not propose an
"optional const", *and - just by the way ;-) - where i could to it...

AFAIK, folks who are sure that the 'do something' parts in those two
functions do not differ at all, simply write a const version and in the
non-const version do the const_cast in and out:

* * *ReturnType const& Function() const
* * *{
* * * * */* do something */
* * *}

* * *ReturnType& Function()
* * *{
* * * * *return const_cast<ReturnType&>(
* * * * * * *const_cast<ThisClass const&>(*this).Function()
* * * * * * *);
* * *}
true for trivial functions, i use this macro for this:

#ifndef INLINE_NC
#define INLINE_NC(ret,fnc,fnnc,cls)\
inline ret fnc {return const_cast<ret>(static_cast<const cls
&>(*this).fnnc);}
#endif

but in not-so trivial cases, i often have to double the code.
struct Something;

Something* GetSomething()
{
SomethingOther* pS = DoSomething();
if (TestSomething(pS)
{
/*.. do something ..*/
return SomethingOther->Something();
} else {
/*.. do something else ..*/
return NULL;
}
}

Something const* GetSomething() const
{
SomethingOther const* pS = DoSomething();
if (TestSomething(pS)
{
/*.. do something ..*/
return SomethingOther->Something();
} else {
/*.. do something else ..*/
return NULL;
}
}
Sep 15 '08 #3
On Sep 15, 3:52 pm, ".rhavin grobert" <cl...@yahoo.dewrote:
[...]
but in not-so trivial cases, i often have to double the code.

struct Something;

Something* GetSomething()
{
SomethingOther* pS = DoSomething();
[...]
}

Something const* GetSomething() const
{
SomethingOther const* pS = DoSomething();
[...]

While your algorithm stays the same for both the const and non-const
member function you operate on different types; hence you need a
template. I guess the problem is that DoSomething uses other member
function that are also overloaded on the constness of the object. The
solution is to make /this/ an explicit parameter of a static member
function template:

Something* GetSomething () {
return DoGetSomething
<Something, SomethingOther(*this);
}

const Something* GetSomething () const {
return DoGetSomething
<const Something, const SomethingOther(*this);
}

template <class S, class SO, class This>
static S* DoGetSomething (This& self) {
SO* p = self.DoSomething ();
if (self.TestSomething (p)) {
/*.. do something ..*/
return p->GetSomething();
} else {
/*.. do something else ..*/
return 0;
}
}

Regards,
Vidar Hasfjord
Sep 15 '08 #4
Victor Bazarov wrote:
.rhavin grobert wrote:
>hello;-)

i frequently need the following construction:

ReturnParam § Function() §

A 'const' in the return type does not matter. The difference, however,
is sometimes like this:

ReturnType Function() const

vs

ReturnType& Function()
I'd say it's

const ReturnType& Function() const

vs

ReturnType& Function()

i.e. reference to const versus reference to non-const...
ReturnType const& Function() const
{
/* do something */
}

ReturnType& Function()
{
return const_cast<ReturnType&>(
const_cast<ThisClass const&>(*this).Function()
);
}
.... and here, you write that, too.

Sep 15 '08 #5
On Sep 15, 6:40*pm, "Alf P. Steinbach" <al...@start.nowrote:
[...]
* Victor Bazarov:
AFAIK, folks who are sure that the 'do something' parts in those two
functions do not differ at all, simply write a const version and in the
non-const version do the const_cast in and out:

Effectively, yes, but regarding syntax they try to avoid 'const_cast'.
[...]
One general code reuse scheme goes like this:

* * private:
* * * * ReturnType& fooImpl() const ...

* * public:
* * * * ReturnType& foo() { return fooImpl(); }
* * * * ReturnType const& foo() const { return fooImpl(); }
While this is often an acceptable solution it is not general. If
fooImpl should need to call other member functions with overload
resolution based on the constness of the object, then this solution
wont work. See code below.

Also, if fooImpl needs to return a reference to a member, as often is
the case, you still need a const_cast inside the implementation; since
fooImpl is const while the return value is not. In that case this
solution is no better than the cast'n'forward idiom.

The fully general and safe solution is to forward to a template
function:

// Const and non-const getter overloads

#include <iostream>
using namespace std;

typedef int X;

class C {
X x_;

public:
C () {}

void foo () {cout << "non-const\n";}
void foo () const {cout << "const\n";}

X& get () {
foo ();
return x_;
}

#if 0 // duplicate algorithm
const X& get () const {
foo ();
return x_;
}
#else // dangerous cast'n'forward idiom
const X& get () const {
return const_cast <C*(this)->get ();
}
#endif

// safe template solution

#if 1 // C++98
X& get2 () {return do_get2 <X(*this);}
const X& get2 () const {return do_get2 <const X(*this);}

template <class R, class This>
static R& do_get2 (This& self) {
self.foo ();
return self.x_;
}
#else // C++0x
X& get2 () {return do_get2 (*this);}
const X& get2 () const {return do_get2 (*this);}

template <class This>
static auto do_get2 (This& self) -decltype (self.x_)& {
self.foo ();
return self.x_;
}
#endif
};
void test_getter_overload ()
{
cout << "Non-const object tests:\n";
C c;
c.get (); // Ok, prints "non-const".
c.get2 (); // Ok, prints "non-const".

cout << "Const object tests:\n";
const C cc;
cc.get (); // Ouch, prints "non-const".
cc.get2 (); // Ok, prints "const".
}

Regards,
Vidar Hasfjord

Sep 15 '08 #6
On Sep 15, 8:25*pm, "Alf P. Steinbach" <al...@start.nowrote:
* Vidar Hasfjord:
[...]
* // safe template solution
#if 1 // C++98
* X& get2 () {return do_get2 <X(*this);}
* const X& get2 () const {return do_get2 <const X(*this);}
* template <class R, class This>
* static R& do_get2 (This& self) {
* * self.foo ();
* * return self.x_;
* }
[...]
I'm too crossed-eyed to really read the code, but I think it's one of those yes,
not "the" but "also one". Credit to some Easter Bloc guy (Russian?). Uh,
I don't follow/know.
correction, I see some "const_cast" above, and no matter how the code works that
shouldn't be there if it's the old code, above is *not* the old Russian scheme.
You misinterpret the example; my code included the cast'n'forward
solution only for illustration.
Anyway, the reason why nobody do such things in practice, but only as academic
exercises, is that it's far too much code size overhead for no real gain.
That's generally true. But for the problem presented by the OP I think
the template solution is appropriate. His common code may very well
depend on overload resolution based on object constness. Only a
template can provide that; unless he duplicates the code.

Regards,
Vidar Hasfjord
Sep 16 '08 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by C. J. Clegg | last post: by
20 posts views Thread by liujiaping | last post: by
1 post views Thread by CARIGAR | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.