C ++ Сравнение стеков общих указателей - PullRequest
0 голосов
/ 19 февраля 2019

Допустим, у меня есть стек, который содержит общие указатели для int, например:

#include <stack>
#include <memory>

using namespace std;

int main()
{
    stack<shared_ptr<int>> s1;
    stack<shared_ptr<int>> s2;

    shared_ptr<int> v1 = make_shared<int>(1);
    shared_ptr<int> v2 = make_shared<int>(1);

    s1.push(v1);
    s2.push(v2);

    bool areEqual = s1 == s2; // This is false
}

Как мне сделать так, чтобы стеки сравнивали фактические значения, на которые указывает shared_ptr, а не указателисами по себе?

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Мне нравится @ ответ RealFresh .Это демонстрирует, как именно «инкапсулирует» защищенную доступность на самом деле.Но приведение ссылки на объектный объект базового класса к ссылке на объектный объект производного класса и последующая обработка этого как одного может быстро привести к неопределенному поведению.

Однако идея извлечения члена c вполне обоснована.Мы можем сделать это без риска UB с помощью простой утилиты:

template<class S>
constexpr decltype(auto) stack_c(S&& s) {
    using base = std::decay_t<S>;
    struct extractor : base {
        using base::c;
    };
    constexpr auto c_ptr = &extractor::c;
    return std::forward<S>(s).*c_ptr;
} 

Благодаря тому, как работает выражение &extractor::c , мы фактически получаем указатель на член base (специализация std::stack) с именем c.Цель extractor - сделать имя общедоступным через объявление использования.

Затем мы пересылаем ссылку на него, сохраняем категорию значений и все.Это капля замены в @ RealFresh's предложении использовать std::equal:

bool areEqual = std::equal(
    stack_c(s1).begin(), stack_c(s1).end(),
    stack_c(s2).begin(), stack_c(s2).end(),
    [](auto const& p1, auto const& p2) {
        return first && second && (p1 == p2 || *p1 == *p2);
    }
); 

Смотрите его вживую

0 голосов
/ 19 февраля 2019

std::stack имеет защищенный элемент c, который является экземпляром базового типа контейнера.Вы можете создать оболочку стека, которая обращается к этой переменной, а затем сравнить содержимое нижележащих контейнеров следующим образом:

#include <iostream>
#include <stack>
#include <memory>
#include <algorithm>

using namespace std;

template<class stack_type>
struct stack_wrapper : stack_type
{
    auto begin() const
    {
        return stack_type::c.begin();
    }

    auto end() const
    {
        return stack_type::c.end();
    }
};

template<class stack_type>
const stack_wrapper<stack_type> &wrap(const stack_type &stack)
{
    return static_cast<const stack_wrapper<stack_type> &>(stack);
}

int main() {
    stack<shared_ptr<int>> s1;
    stack<shared_ptr<int>> s2;

    shared_ptr<int> v1 = make_shared<int>(1);
    shared_ptr<int> v2 = make_shared<int>(1);

    s1.push(v1);
    s2.push(v2);

    const auto &s1wrapper = wrap(s1);
    const auto &s2wrapper = wrap(s2);

    const auto is_equal = std::equal(s1wrapper.begin(),
        s1wrapper.end(),
        s2wrapper.begin(),
        s2wrapper.end(),
        [](auto &first, auto &second) {
            return first && second && *first == *second;
        });

    std::cout << is_equal << std::endl;
}
...