Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call other class' const member function via a std::unique_ptr member

While reading about a proposal for adding a const-propagating wrapper to the standard library (doc. no. N4388), I bumped into the example given in the paper:

#include <memory>
#include <iostream>

struct A
{
    void bar() const
    {
        std::cout << "A::bar (const)" << std::endl;
    }

    void bar()
    {
        std::cout << "A::bar (non-const)" << std::endl;
    }
};

struct B
{
    B() : m_ptrA(std::make_unique<A>()) {}

    void foo() const
    {
        std::cout << "B::foo (const)" << std::endl;
        m_ptrA->bar(); // calls A::bar() (non-const)

        // const_cast<const std::unique_ptr<A>>(m_ptrA)->bar(); // how to call the A::bar() const?
    }

    void foo()
    {
        std::cout << "B::foo (non-const)" << std::endl;
        m_ptrA->bar();
    }

    std::unique_ptr<A> m_ptrA;
};

int main()
{
    const B const_b;
    const_b.foo();
}

which outputs:

B::foo (const)
A::bar (non-const)

I understand why this happens. Even if the pointer is const, the object it points to is non-const, so indeed the non-const member function A::bar is called (this is the whole point of the proposal in the paper, to avoid this seemingly awkward situation and propagate const via a wrapper). Furthermore, they say that to avoid this situation, once can const_cast the pointer m_ptrA in B::foo() const, so it calls the desired A::bar() const.

I tried countless combinations but frankly I don't know how to const_cast the unique_ptr. Namely, how can I enforce in B::foo() const the "right" call to A::bar() const via the m_ptrA? (see also the comment in the code if it's not entirely clear what I want).

like image 318
vsoftco Avatar asked Apr 16 '15 18:04

vsoftco


1 Answers

You need to const-cast the stored pointer, not unique_ptr:

const_cast<const A*>(m_ptrA.get())->bar();
const_cast<const A&>(*m_ptrA).bar();
like image 60
StenSoft Avatar answered Oct 10 '22 09:10

StenSoft