tags:

views:

102

answers:

3

I seem to have this pattern occuring pretty often in my code, with two functions performing the same task apart from the constness of their parameters/returns.

int& myClass::getData()
{
        return data;
}

// called for const objects 
const int& myData::getData() const
{
        return data;
}

This offends my sense of DRY. It's not a problem for a one-liner, but as getData() gets bigger, there's obvious duplication.

I know WHY I need both methods, but feel there should be a better way to implement it. Is there a template trick that can help, or should I have one method which calls the other casting the constness back and forth as required?

ADDED: As a more real-world example, here's a sample of typical STL vector::at() implementation:

const_reference at(size_type _Off) const
    {   // subscript nonmutable sequence with checking
    if (size() <= _Off)
        _Xran();
    return (*(begin() + _Off));
    }

reference at(size_type _Off)
    {   // subscript mutable sequence with checking
    if (size() <= _Off)
        _Xran();
    return (*(begin() + _Off));
    }
+2  A: 

Providing a function like:

int& myClass::getData()
{
    return data;
}

is probably wrong - you might as well make 'data' public. And the second should be written as:

int myData::getData() const
{
   return data;
}
anon
OK, so the example was rather oversimplified. Return types are typically iterators, and the functions don't just return "data".
Roddy
anon
Yes, but you've got to return const or non-const iterators accordingly.
Roddy
+3  A: 

Use the following trick (which I originally got from Scott Meyers' book Effective C++):

int& myClass::getData()
{
    // This is safe because we know from out here
    // that the return value isn't really const
    return const_cast<int&>(const_cast<const myClass&>(*this).getData());
}

const int& myData::getData() const
{
    return data;
}

Obviously for a short function like this, you may find it easier just to duplicate code, but this idiom is useful when you have a longer function (like vector<T>::at or it is subject to lots of changes.

coppro
Thanks - that's the kind of const casting I was considering. I'll have to reread Meyers' book...
Roddy
To me that looks like a maintenance time bomb.
Georg Fritzsche
Ironically, I think the motivation for it is to reduce the maintenance load.
John Dibling
Yeah. It looks like one, but it isn't. Any change to the logic goes in the `const` version. The non-`const` one stays the same no matter what goes on, except for a change of return type (in which case it would have needed to be changed anyways, so no big deal).
coppro
@coppro: Which edition of Effective C++? - I have 2nd and can't find it...
Roddy
3rd edition, which added a bunch of things to 2nd. I guess this is one of them.
coppro
+1  A: 

The reason the Standard Library functions you quote duplicate the code is that Standard Library functions need to be as performant as possible. Putting a call to another function in there (as others have correctly suggested doing) might screw that. But your code is probably under much less stringent performance constraints, so you should use common code, where possible.

anon
This sounds plausible at first, but thinking about it more, STL is only even remotely "performant" (by which I assume you mean fast and/or compact) with an optimizing compiler - and coppro's answer would surely get optimized. "Const" never affects generated code, only the compilers willingness to compile it...
Roddy