std :: bind vs std :: shared_ptr

0

Не могу понять, как использовать shared_ptr, привязанный к функции класса. Ошибка возникает в строке USE, потому что компилятор не может преобразовать shared_ptr в A.

#include <functional>

class A {
    public:
        const bool check(void) const { return true; };
};

int _tmain(int argc, _TCHAR* argv[]) {
    const std::function<const bool(const A)> f_check = &A::check;
    auto a = std::make_shared<const A>();
    auto f_check_a = std::bind(f_check, a); // line BIND
    auto res = f_check_a(); // line USE - ERROR!!!

    return 0;
}

Я могу заменить строку BIND на доступ к реальному значению смарт-указателя:

int _tmain(int argc, _TCHAR* argv[]) {
    auto f_check = &A::check;
    auto a = std::make_shared<const A>();
    auto f_check_a = std::bind(f_check, *a.get()); // line BIND
    auto res = f_check_a(); // line USE - NO ERRORS

    return 0;
}

Теперь код скомпилирован и, возможно, он будет работать. Но я хотел бы знать - приемлемый ли способ использовать исходную ценность из умного указателя? Могу ли я каким-то образом использовать shared_ptr вместо необработанного значения?

UPD2: Похоже, мой коллега нашел приятное обходное решение:

class A {
    public:
        const bool check(void) const { return true; };
};

using p_func = const bool(A::*)() const;

int _tmain(int argc, _TCHAR* argv[]) {
    auto a = std::make_shared<const A>();
    p_func b = &A::check;
    auto f_check_a = std::bind(b, a);
    auto res = f_check_a();
}

Теперь я могу отправить b как аргумент и привязать к shared_ptr.

UPD: Я не могу использовать лямбда в своей реальной задаче. Вот еще код из реального проекта:

#include <functional>
#include <algorithm>

class Block {
    public:
        const bool check1(void) const { return false; };
        const bool check2(void) const { return false; };
        const bool check3(void) const { return false; };
};

using block_t = std::shared_ptr<const Block>;

class Worker {
    private:
        std::vector<const block_t> _container;
    public:
        void processor(const std::function<const bool(const Block)> f_check) {
            block_t my_block = nullptr;
            auto lambda = [my_block, f_check](const block_t block) mutable {
                auto function_check = std::bind(f_check, *block.get());
                if (function_check()) {
                    my_block = block;
                    return true;
                }
                return false;
            };
            std::find_if(_container.begin(), _container.end(), lambda);
        }
};

void test(block_t block) {
    Worker worker;
    worker.processor(&Block::check1);
    worker.processor(&Block::check2);
    worker.processor(&Block::check3);
}

UPD3: исправлен код без разыменования интеллектуальных указателей:

#include <functional>
#include <algorithm>

class Block {
public:
    const bool check1(void) const { return false; };
    const bool check2(void) const { return false; };
    const bool check3(void) const { return false; };
};

using block_t = std::shared_ptr<const Block>;
using p_func = const bool(Block::*)() const;

class Worker {
private:
    std::vector<const block_t> _container;
public:
    void processor(p_func f_check) {
        block_t my_block = nullptr;
        auto lambda = [my_block, f_check](const block_t block) mutable {
            auto function_check = std::bind(f_check, block);
            if (function_check()) {
                my_block = block;
                return true;
            }
            return false;
        };
        std::find_if(_container.begin(), _container.end(), lambda);
    }
};

void test(block_t block) {
    Worker worker;
    worker.processor(&Block::check1);
    worker.processor(&Block::check2);
    worker.processor(&Block::check3);
}
  • 0
    Я не понимаю, почему вы не можете заменить строку std::bind лямбда-выражением.
  • 0
    У меня нет экземпляра объекта при вызове методов check1..3, на стороне клиента я могу отправить только ссылку на функцию класса, которая должна обрабатывать коллекцию.
Показать ещё 10 комментариев
Теги:
c++11
shared-ptr
std
bind

4 ответа

3

Ваша проблема в том, что вы сначала создаете std::function, ожидая экземпляр A, от функции-члена и пытаетесь связать его с shared_ptr. Вы можете пропустить эту часть:

auto a = std::make_shared<const A>();
auto f_check_a = std::bind(&A::check, a);
auto res = f_check_a(); 

std::bind знает, как напрямую привязывать функцию-член к shared_ptr.

  • 0
    Это не будет работать - то же неопределенное приведение от shared_ptr к A.
  • 1
    @adnako Странно, протестировано с MSVC 2010 и скопировано.
Показать ещё 1 комментарий
2

Должны ли вы использовать std::bind? Вместо этого вы можете использовать лямбду.

auto f_check_a = [=]{ return a->check(); };
  • 0
    Я разместил больше кода, пожалуйста, проверьте его. Я не могу использовать лямбду в моем случае.
1

Но я хотел бы знать - приемлемый ли способ использовать исходную ценность из умного указателя?

Да, но вы можете просто написать *a вместо *a.get()

Тем не менее, оболочка вызовов, возвращаемая из bind имеет ссылку на объект A, поэтому вы несете ответственность за то, чтобы ссылка оставалась действительной. Если вы связали shared_ptr, это увеличит количество ссылок и сохранит объект.

Могу ли я каким-то образом использовать shared_ptr вместо необработанного значения?

Если вы используете std::function<const bool(const A)> вы не можете передать shared_ptr<const A>.

Когда вы используете std::function<const bool(const A)> вы создаете вызываемый тип, который имеет точно подпись вызова const bool(const A) и поэтому вы должны передать ему аргумент, который можно преобразовать в const A и shared_ptr<const A> не преобразуется в const A

Обходным решением было бы использовать лямбда для объединения std::function и shared_ptr:

            auto function_check = [] { return f_check(*block); };
            if (function_check()) {

Однако вы пытаетесь решить проблему, которая не должна существовать, просто сделайте это вместо этого:

            if (f_check(*block)) {
                my_block = block;
                return true;
            }
            return false;

Тогда вам не нужно ничего bind.

  • 0
    Да, я могу выбросить привязку, если я использую разыменование, спасибо, например. Но я просто пытаюсь избежать ответственности за наблюдение за жизненными циклами указателей. И похоже, что я нашел решение, посмотрите на UPD3, пожалуйста.
  • 0
    Эта bind в UPD3 все еще бесполезна. std::mem_fn(f_check)(*block) тоже будет работать или просто ((*block).*f_check)() . Я не понимаю, почему вы боитесь разыменования, почему вы усложняете свой код, чтобы избежать его? block передается в функцию замыкания, его время жизни не закончится, пока вы не разыграете его. О чем ты беспокоишься?
Показать ещё 4 комментария
1

function ожидает получить экземпляр A, а не shared_ptr<A>, поэтому ответ на ваш вопрос в основном да, я считаю.

Однако я бы сделал 2 изменения в вашем коде следующим образом (см. Мои комментарии):

const std::function<const bool(const A&)> f_check = &A::check; // <-- Added & after A here
auto a = std::make_shared<const A>();
auto f_check_a = std::bind(f_check, *a); // <-- no need to call get() on a
auto res = f_check_a(); // line USE - ERROR!!!
  • 0
    «<- не нужно вызывать get () для a» - это не то же самое, но на несколько символов меньше? Проверьте мой код обновления, пожалуйста.
  • 0
    @adnako: Это верно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню