Не могу понять, как использовать 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);
}
Ваша проблема в том, что вы сначала создаете 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
.
Должны ли вы использовать std::bind
? Вместо этого вы можете использовать лямбду.
auto f_check_a = [=]{ return a->check(); };
Но я хотел бы знать - приемлемый ли способ использовать исходную ценность из умного указателя?
Да, но вы можете просто написать *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
.
bind
в UPD3 все еще бесполезна. std::mem_fn(f_check)(*block)
тоже будет работать или просто ((*block).*f_check)()
. Я не понимаю, почему вы боитесь разыменования, почему вы усложняете свой код, чтобы избежать его? block
передается в функцию замыкания, его время жизни не закончится, пока вы не разыграете его. О чем ты беспокоишься?
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!!!
std::bind
лямбда-выражением.