dchhetri
dchhetri

Reputation: 7136

Is it okay to remove const qualifier when the call is from the same non-const version overloaded member function?

For example:

struct B{};

struct A {

 const B& findB() const { /* some non trivial code */ }

 // B& findB() { /* the same non trivial code */ }

 B& findB() { 
       const A& a = *this;
       const B& b = a.findB();
       return const_cast<B&>(b);
  }
};

The thing is I want to avoid repeating the same logic inside the constant findB and non-constant findB member function.

Upvotes: 6

Views: 1938

Answers (2)

Jon Purdy
Jon Purdy

Reputation: 54979

Yes, you can cast the object to const, call the const version, then cast the result to non-const:

return const_cast<B&>(static_cast<const A*>(this)->findB());

Casting away const is safe only when the object in question was not originally declared const. Since you are in a non-const member function, you can know this to be the case, but it depends on the implementation. Consider:

class A {
public:

    A(int value) : value(value) {}

    // Safe: const int -> const int&
    const int& get() const {
        return value;
    }

    // Clearly unsafe: const int -> int&
    int& get() {
        return const_cast<int&>(static_cast<const A*>(this)->get());
    }

private:
    const int value;
};

Generally speaking, my member functions are short, so the repetition is tolerable. You can sometimes factor the implementation into a private template member function and call that from both versions.

Upvotes: 8

Lol4t0
Lol4t0

Reputation: 12547

I think, that using cast here is ok, but if you definitely want to avoid it, you can use some template magic:

struct B
{
    B(const B&)
    {
        std::cout << "oops I copied";
    }
    B(){}
};

struct A {
public:
    A(){}
    A(const A&){ std::cout << "a is copied:(\n";}
    const B& findB() const { return getter(*this); }    
    B& findB() { return getter(*this); }

private:
    template <typename T, typename V>
    struct same_const
    {
        typedef V& type;
    };

    template <typename T, typename V>
    struct same_const<const T, V>
    {
        typedef const V& type;
    };

    template <typename T>
    static typename same_const<T,B>::type getter(T& t) { return t.b;}

    B b;

};

int main()
{
    A a;
    const A a_const;
    const B& b1 = a.findB();
    B& b2 = a.findB();

    const B& b3 = a_const.findB();
    //B& b4 = a_const.findB();
}

Upvotes: 1

Related Questions