Как вызвать функцию-член const другого класса через член std::unique_ptr

Читая о предложении добавить в стандартную библиотеку оболочку, распространяющую константу (№ документа N4388), я наткнулся на пример, приведенный в статье:

#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();
}

который выводит:

B::foo (константа)
A::bar (неконстанта)

Я понимаю, почему это происходит. Даже если указатель равен const, объект, на который он указывает, не является константным, поэтому действительно вызывается неконстантная функция-член A::bar (в этом весь смысл предложения в документе, чтобы избежать этой, казалось бы, неловкой ситуации и распространить const через обертку). Кроме того, говорят, что во избежание такой ситуации можно один раз const_cast m_ptrA указать в B::foo() const, чтобы он вызывал нужный A::bar() const.

Я пробовал бесчисленное количество комбинаций, но, честно говоря, я не знаю, как const_cast unique_ptr. А именно, как я могу обеспечить в B::foo() const "правильный" вызов A::bar() const через m_ptrA? (см. также комментарий в коде, если не совсем понятно, что я хочу).


person vsoftco    schedule 16.04.2015    source источник


Ответы (1)


Вам нужно константно указать сохраненный указатель, а не unique_ptr:

const_cast<const A*>(m_ptrA.get())->bar();
const_cast<const A&>(*m_ptrA).bar();
person StenSoft    schedule 16.04.2015
comment
Спасибо, это действительно работает. По какой-то причине я подумал, что могу использовать const_cast непосредственно на умном указателе, подобно static_pointer_cast для shared_ptr. Но ваше решение, вероятно, единственное. - person vsoftco; 16.04.2015
comment
@vsoftco const_cast в интеллектуальном указателе изменяет константность интеллектуального указателя, но operator -> и operator * интеллектуального указателя не сохраняют константность для возвращаемого объекта. Это имитирует поведение необработанных указателей. Если вам нужен указатель, сохраняющий константу, вы можете использовать эту реализацию. - person StenSoft; 18.04.2015