Can't understand how to use shared_ptr binded to class function.
An error occurrs at line USE because compiler can't convert shared_ptr to 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;
}
I can replace line BIND to access real value of smart pointer:
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;
}
Now code is compiled and may be it will work.
But I'd like to know - is it acceptable way to use raw value from smart pointer? May I somehow use shared_ptr instead raw value?
UPD2:
Looks like my colleague have found a nice workaround:
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();
}
Now I can send b as argument and bind to shared_ptr.
UPD:
I can't use lambda in my real task.
Here is some more code from real project:
#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:
Fixed code without smart pointer dereferencing:
#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);
}
Your problem is that you are first creating a std::function, expecting an A instance, from a member function and than trying to bind it to a shared_ptr. You can skip that part:
auto a = std::make_shared<const A>();
auto f_check_a = std::bind(&A::check, a);
auto res = f_check_a();
std::bind knows how to directly bind a member function to a shared_ptr.
Must you use std::bind? You could use a lambda instead.
auto f_check_a = [=]{ return a->check(); };
function expects to get an instance of A, not a shared_ptr<A>, so the answer to your question is basically yes, I believe.
However, I would make 2 changes to your code as follows (see my comments):
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!!!
But I'd like to know - is it acceptable way to use raw value from smart pointer?
Yes, but you can just write *a instead of *a.get()
However, the call wrapper returned from bind has a reference to theA object, so it is your responsibility to ensure the reference remains valid. If you bound the shared_ptr then that would increase the reference count and keep the object alive.
May I somehow use shared_ptr instead raw value?
If you use std::function<const bool(const A)> then you cannot pass a shared_ptr<const A>.
When you use std::function<const bool(const A)> you create a callable type that has exactly the call signature const bool(const A) and so you have to pass it an argument that is convertible to const A, and shared_ptr<const A> is not convertible to const A.
A workaround would be to use a lambda to combine the std::function and shared_ptr:
auto function_check = [] { return f_check(*block); };
if (function_check()) {
However, you are trying to solve a problem that shouldn't exist, just do this instead:
if (f_check(*block)) {
my_block = block;
return true;
}
return false;
Then you don't need to bind anything.
Related
I am doing something like this with TBB:
#include <tbb/tbb.h>
#include <memory>
#include <atomic>
class base_creator
{
public:
using node = tbb::flow::input_node<bool>;
virtual ~base_creator() = default;
base_creator()
{
m_kill = std::make_shared<std::atomic_bool>(false);
};
static tbb::flow::graph& g()
{
static tbb::flow::graph me_g;
return me_g;
};
virtual std::shared_ptr<node> get_node() const = 0;
template<typename Op>
static tbb::flow::input_node<bool> build_node(const Op& op)
{
return tbb::flow::input_node<bool>(base_creator::g(), op);
};
protected:
mutable std::shared_ptr<std::atomic_bool> m_kill;
};
class creater : public base_creator
{
public:
creater() = default;
public:
virtual std::shared_ptr<node> get_node() const override
{
const std::shared_ptr<std::atomic_bool> flag = this->m_kill;
auto op = [flag](flow_control& control) -> bool
{
if (flag->load(std::memory_order_relaxed))
control.stop();
return true;
};
node nd = base_creator::build_node(std::cref(op));
return std::make_shared<node>(nd);
};
};
int main(int argc, char* argv[])
{
creater c;
std::shared_ptr<base_creator::node> s = c.get_node();
using my_func_node = std::shared_ptr<tbb::flow::function_node<bool, bool>>;
my_func_node f = std::make_shared<tbb::flow::function_node<bool, bool>>(base_creator::g(), 1,[](const bool b) { std::cout << b; return b; });
tbb::flow::make_edge(*s, *f);
};
The flag should be always false in this code. Once I call tbb::flow::make_edge it becomes true when debugging the body of the node s in THAT IS SO WEIRD? I have no clue, could you please help, I am starting to hit in the TBB code now and it's too complex :)
Pay attention to the following code. It creates std::reference_wrapper over local object op that is copied into input_node with build_node. Therefore, when get_node returns the std::reference_wrapper (that is inside the node that is inside shared_ptr), it references the destroyed object. Then, make_edge reuses the stack and replaces flag pointer with some other pointer that contains 72.
auto op = [flag](flow_control& control) -> bool
{
if (flag->load(std::memory_order_relaxed))
control.stop();
return true;
};
node nd = base_creator::build_node(std::cref(op));
I wrote the code below,
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = dlsym(handle_), "foo");
When i use any_cast
return (std::any_cast<void(*)()>(symbols_["foo"]))();, the program will throw a error: bad any_cast.
I found the main reason because of the function .
template<typename _Tp>
void* __any_caster(const any* __any)
It would judge the condition as false and then return nullptr.
else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage
#if __cpp_rtti
|| __any->type() == typeid(_Tp)
#endif
){
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
}
return nullptr;
I want to know
1.why __any->_M_manager == &any::_Manager<_Up>::_S_manage and __any->type() == typeid(_Tp) were all false,
2.and how can i fix the problem(continue to use std::any).
Here is a simple demo.
#include <any>
void func() { }
auto main() -> int {
std::any a = (void*)func;
std::any_cast<void(*)()>(a)();
return 1;
}
gcc version 10.1.0 (GCC)
Here you store a void* in the std::any object:
symbols_["foo"] = dlsym(handle_, "foo");
To instead store a void(*)(), you need to cast the void* that's returned by dlsym:
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_, "foo"));
In this case, you may want to just store the void* and cast when using it instead:
std::unordered_map<std::string_view, void*> symbols_;
symbols_["foo"] = dlsym(handle_, "foo");
//...
return reinterpret_cast<void(*)()>(symbols_["foo"])();
A third option, if you don't need the runtime lookup in the unordered_map, is to instead store the function pointers in named variables. That makes the usage a little easier. Here's an example:
A generic class for loading/unloading a shared library:
class Lib {
public:
explicit Lib(const char* filename, int flags = RTLD_LAZY) :
lib(dlopen(filename, flags))
{
if(!lib) throw std::runtime_error(dlerror());
}
Lib(const Lib&) = delete;
Lib(Lib&& rhs) = delete;
Lib& operator=(const Lib&) = delete;
Lib& operator=(Lib&& rhs) = delete;
virtual ~Lib() { dlclose(lib); }
private:
struct cast_proxy { // a class to cast to the proper pointer
// cast to whatever that is needed:
template<class Func>
operator Func () { return reinterpret_cast<Func>(sym); }
void* sym;
};
protected:
cast_proxy sym(const char* symbol) const {
void* rv = dlsym(lib, symbol);
if(rv) return {rv}; // put it in the cast_proxy
throw std::runtime_error(dlerror());
}
private:
void* lib;
};
A class for loading a specific shared library:
class YourLib : public Lib {
public:
YourLib() : Lib("./libyour_library.so"),
// load all symbols here:
foo(sym("foo")) // the cast proxy will return the correct pointer type
{}
// Definitions of all the symbols you want to load:
void(*const foo)();
};
Then using it will be as simple as this:
int main() {
YourLib ml;
ml.foo();
}
std::any_cast will only cast back to the type that was stored in the std::any. As dlsym returns void*, that is what is stored in the std::any.
You need a separate cast to void(*)() either before storing in std::any or after the std::any_cast:
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_), "foo"));
return (std::any_cast<void(*)()>(symbols_["foo"]))();
My application compiler could only support up to c++11.
Below is a snip code of my project and function get_conn() returns std::unique_ptr with custom deleter (deleter needs two arguments). I'm using auto keyword for return type but it gives an error like if is compiled with c++11 (compiles fine with c++14)
error: ‘get_conn’ function uses ‘auto’ type specifier without trailing return type
Sample code for demonstration:
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
// Dummy definition of API calls
int* open_conn (int handle)
{
return new int;
}
void close_conn (int handle, int *conn)
{}
auto get_conn (int handle)
{
// API call
int* conn = open_conn (handle);
auto delete_conn = [](int *conn, int handle) {
// API call
close_conn (handle, conn);
delete conn;
};
auto delete_binded = std::bind (delete_conn, std::placeholders::_1, handle);
return std::unique_ptr<int, decltype(delete_binded)> (conn, delete_binded);
}
int main()
{
int handle = 2; // suppose
auto c = get_conn (handle);
if (!c)
cout << "Unable to open connection\n";
return 0;
};
How can I replace auto keyword with actual return type of std::unique_ptr to compatible code with c++11 ?
I tried with below return type but failed
std::unique_ptr<int, void(*)(int *,int)> get_conn(int handle)
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
// ...
}
Back to the functor!
The auto return type for functions is c++14 feature. In order to provide the actual return type, you can provide a functor like follows(as #IgorTandetnik mentioned in the comments). The advantage is, that you do not need to std::bind any more.
(See online)
struct DeleteConn // functor which subsituts the lambda and `std::bind`
{
int _handle;
explicit DeleteConn(int handle): _handle{ handle } {}
void operator()(int* conn) const
{
// API call
close_conn(_handle, conn);
delete conn;
}
};
std::unique_ptr<int, DeleteConn> get_conn(int handle)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---> now you can provide the actual type.
{
// API call
int* conn = open_conn(handle);
DeleteConn delete_conn{ handle };
return std::unique_ptr<int, DeleteConn>(conn, delete_conn);
}
Alternatively, you can move the lambda function delete_conn out from the get_conn function and use the trailing return type which is a c++11 fetaure.
(See Online)
namespace inter {
auto delete_conn = [](int* conn, int handle)
{
// API call
close_conn(handle, conn);
delete conn;
};
}
auto get_conn(int handle)
->std::unique_ptr<int, decltype(std::bind(inter::delete_conn, std::placeholders::_1, handle))>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --->Trailing return type
{
// API call
int* conn = open_conn(handle);
auto delete_binded = std::bind(inter::delete_conn, std::placeholders::_1, handle);
return std::unique_ptr<int, decltype(delete_binded)>(conn, delete_binded);
}
Your lambda is passed into std::bind, so you get another unnamed object, about which you know only it has void (int*) signature.
int as second param was bound, so it is mistake to put it in signature like void(*)(int *,int). This functor takes only pointer to int.
Use std::function:
std::unique_ptr<int, std::function<void(int*)>>
get_conn (int handle)
{
// API call
int* conn = open_conn (handle);
auto delete_conn = [](int *conn, int handle)
{
// API call
close_conn (handle, conn);
delete conn;
};
auto delete_binded = std::bind (delete_conn, std::placeholders::_1, handle);
return std::unique_ptr<int, std::function<void(int*)> > (conn, delete_binded);
}
Demo
I have a class named Handler wich stores some lambdas. What I want to do is to have a std::vector of std::function that stores all my events, for exemple. I really can't figure out why lambdas doesn't work as I expected.
Here's the handler.h:
class Handler
{
public:
Handler();
~Handler();
void Register(const char* outcome, std::function<auto()> lambda);
void Trigger(const char* outcome);
private:
std::vector<int> identifier;
std::vector<char*> outcome;
std::vector<std::function<auto()>> func;
};
And handler.cpp:
Handler::Handler()
{
//ctor stuff here
}
Handler::~Handler()
{
this->func.clear();
this->outcome.clear();
this->identifier.clear();
//...
}
void Handler::Register(const char* outcome, std::function<auto()> lambda)
{
static int identifier = 0;
identifier++;
this->outcome.push_back((char*)outcome);
this->identifier.push_back(identifier);
this->func.push_back(lambda);
//Sort outcome
}
void Handler::Trigger(const char * outcome)
{
int i;
for (i = 0; i < this->identifier.size(); i++)
{
if (!strcmp(outcome, this->outcome.at(i)))
break;
}
this->func[i]();
}
However, if I specify lambdas in a Handler::Register it wont let me throwing no suitable user-defined conversion from "lambda []void ()->void" to "std::function<auto()> exists. In this example I use void return type but other types also error, I don't understant why can't the template from std::function deduce it out, if it is what's happening.
Handler* events = new Handler();
events->Register("Up", [=]() -> void { //Error here!
//do stuff
//return something?
});
Is there any other way to do this, like without overloading Handler::Register?
auto is not a type, so std::function<auto()> is not a type either. From how you are using it, std::function<void()> is probably what you want.
There are other problems with your code, as noted in the comments, so I would change Handler to this
class Handler
{
public:
Handler();
// default ~Handler is fine
void Register(std::string outcome, std::function<void()> lambda);
void Trigger(const std::string & outcome outcome) const;
void Trigger(std::size_t index) const;
private:
using Outcomes = std::map<std::string, std::function<void()>/*, custom string comparator ?*/>;
std::vector<Outcomes::iterator> identifier;
Outcomes outcomes;
};
void Handler::Register(std::string outcome, std::function<void()> func)
{
auto emplaced = outcomes.emplace(std::move(outcome), std::move(func));
identifier.push_back(emplaced.first);
}
void Handler::Trigger(const std::string & outcome) const
{
outcomes.at(outcome)();
}
void Handler::Trigger(std::size_t index) const
{
identifier[index]->second();
}
This is my attempt:
#include <iostream>
#include <functional>
class Voice;
class EnvelopeMultiPoints
{
public:
std::function<double(Voice &, double)> mCallback;
void SetupModulation(std::function<double(Voice &, double)> callback, int paramID) {
mCallback = callback;
}
};
class Voice
{
public:
EnvelopeMultiPoints mEnvelopeMultiPoints;
};
class VoiceManager
{
public:
Voice mVoices[16];
inline void UpdateVoices(std::function<void(Voice &)> callback) {
for (int i = 0; i < 16; i++) {
callback(mVoices[i]);
}
}
static void SetupEnvelopeMultiPointsModulation(Voice &voice, std::function<double(Voice &, double)> callback, int paramID) {
voice.mEnvelopeMultiPoints.SetupModulation(callback, paramID);
}
};
class Oscillator
{
public:
double ModulatePitch(Voice &voice, double currentValue) {
// somethings with voice
return currentValue * 10.0;
}
};
int main()
{
VoiceManager voiceManager;
Oscillator *pOscillator = new Oscillator();
int param = 100;
auto callback = std::bind(&Oscillator::ModulatePitch, pOscillator, std::placeholders::_1, std::placeholders::_2);
voiceManager.UpdateVoices(std::bind(&VoiceManager::SetupEnvelopeMultiPointsModulation, std::placeholders::_1, callback, param));
Voice voice = voiceManager.mVoices[0];
std::cout << voice.mEnvelopeMultiPoints.mCallback(voice, 1.0) << std::endl;
delete pOscillator;
}
I create a sort of Voice Updater "basic" iterator, which I can pass any kind of functions later. It iterates all voices and pass the function I need for that iteration.
But it seems I'm wrong on bind the Oscillator::ModulatePitch function to pass to the Updater?
Where am I wrong here?
As pergy wrote in its comment, if you use std::function<double(Voice &, double)> callback = ... instead of auto, it works. The reason is that it forces a conversion from an bind object to a std::function.
If you do
auto callback1 = std::bind(&Oscillator::ModulatePitch, pOscillator, std::placeholders::_1, std::placeholders::_2);
std::function<double(Voice &, double)>callback2 = std::bind(&Oscillator::ModulatePitch, pOscillator, std::placeholders::_1, std::placeholders::_2);
std::cout << typeid(callback1).name();
std::cout << typeid(callback2).name();
you will see that the returning types are differents. And in this case, the second bind tries to build its object using the second type (which does not work). I think there is an issue with the conversion operator (from bind to std::function) not being called by the external bind.