boost::bind, boost::shared_ptr and inheritance - c++

I'm new with the Boost library, and I got a problam a bit complex for me.
I tried to reformulate it with an example found in previous question that might fit well my problem.
(The previous question is here)
#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
class Base
: public boost::enable_shared_from_this<Base>,
private boost::noncopyable
{
public:
virtual void test() = 0;
protected:
virtual void foo(int i) = 0;
};
class Derived
: public Base
{
protected:
void foo(int i)
{ std::cout << "Base: " << i << std::endl; }
std::map<int, int> data;
public:
Derived()
{
data[0] = 5;
data[1] = 6;
data[2] = 7;
}
void test()
{
std::for_each(data.begin(), data.end(),
boost::bind(&Derived::foo, shared_from_this(),
boost::bind(&std::map<int, int>::value_type::second, _1)));
}
};
typedef boost::shared_ptr<Base> Base_ptr;
int main(int, const char**)
{
std::set<Base_ptr> Bases_;
Base_ptr derived(new Derived());
Bases_.insert(derived);
derived->test();
return 0;
}
I have a base object which is contained in a set, and different derived objects (in this example, only one).
The derived object should call his own protected method with a boost::bind.
In the real problem, the boost::bind generate a callback method for an asynchronous operation, it's why (I think) I need a shared_ptr.
Otherwise, using the pointer this instead of shared_from_this() resolve the problem.
When I compile this code, I got a long error message ended with (which I think is the most significant part):
bind_test.cpp:43:78: instantiated from here
/usr/include/boost/bind/mem_fn_template.hpp:156:53: error: pointer to member type ‘void (Derived::)(int)’ incompatible with object type ‘Base’
/usr/include/boost/bind/mem_fn_template.hpp:156:53: error: return-statement with a value, in function returning 'void'
I tried to manage with more inheritance from enable_shared_from_this, and some static cast :
#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
class Base
: public boost::enable_shared_from_this<Base>,
private boost::noncopyable
{
public:
virtual void test() = 0;
protected:
virtual void foo(int i) = 0;
};
class Derived
: public boost::enable_shared_from_this<Derived>,
public Base
{
protected:
void foo(int i)
{ std::cout << "Base: " << i << std::endl; }
std::map<int, int> data;
public:
Derived()
{
data[0] = 5;
data[1] = 6;
data[2] = 7;
}
void test()
{
std::for_each(data.begin(), data.end(),
boost::bind(&Derived::foo, boost::enable_shared_from_this<Derived>::shared_from_this(),
boost::bind(&std::map<int, int>::value_type::second, _1)));
}
};
typedef boost::shared_ptr<Base> Base_ptr;
int main(int, const char**)
{
std::set<Base_ptr> Bases_;
Base_ptr derived(new Derived());
Bases_.insert(derived);
derived->test();
return 0;
}
But I got an error at run-time :
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_weak_ptr> >'
what(): tr1::bad_weak_ptr
Might someone have a clue about how to manage that ?
Thanks.
Etienne.

It works with this workaround, but I'm not satisfied with it, so if someone find a better solution, go ahead.
#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
class Base
: public boost::enable_shared_from_this<Base>,
private boost::noncopyable
{
public:
virtual void test() = 0;
//protected:
virtual void foo(int i) = 0;
};
class Derived
: public Base
{
protected:
void foo(int i)
{ std::cout << "Base: " << i << std::endl; }
std::map<int, int> data;
public:
Derived()
{
data[0] = 5;
data[1] = 6;
data[2] = 7;
}
void test()
{
std::for_each(data.begin(), data.end(),
boost::bind(&Base::foo, shared_from_this(),
boost::bind(&std::map<int, int>::value_type::second, _1)));
}
};
typedef boost::shared_ptr<Base> Base_ptr;
int main(int, const char**)
{
std::set<Base_ptr> Bases_;
Base_ptr derived(new Derived());
Bases_.insert(derived);
derived->test();
return 0;
}

Related

Create a constructor for a shared_ptr<MyClass>

#include <iostream>
#include <vector>
class TestX {
public:
int i;
TestX(int inp1) : i(inp1){}
};
using Test = std::shared_ptr<TestX>;
int main()
{
Test a(4);
std::cout << a->i << std::endl;
}
I wanted to hide away that I am using a shared pointer, and make it look like I have just a regular class. The reason is that it is essential that my objects are never copied, but I still want the users to be able to create a vector with {obj1, obj2}. Is there a way to initialize a Test object as if there was a constructor, or do I have to use make_shared to initialize it?
You can use a class to wrap a std::shared_ptr, as follows
#include <iostream>
#include <vector>
#include <memory>
struct TestX {
int i;
TestX(int inp1) : i(inp1){}
TestX(TestX const &) = delete;
};
struct Test {
std::shared_ptr<TestX>test;
Test(int inp1) : test{std::make_shared<TestX>(inp1)}{}
int& get_i (){
return test -> i;
}
};
int main()
{
Test a(4);
Test b(1);
auto v = std::vector{a, b};
std::cout << a.get_i() << std::endl;
}
you can also derive from shared_ptr<TestX>
#include <iostream>
#include <vector>
#include <memory>
class TestX {
public:
int i;
TestX(int inp1) : i(inp1){}
};
struct Test : std::shared_ptr<TestX>{
Test( int x) : std::shared_ptr<TestX>{std::make_shared<TestX>(x)}{}
};
int main()
{
Test a(4);
std::cout << a->i << std::endl;
Test b(1);
auto v = std::vector{a, b};
}

C++ (14) - googletest undefined identifier

I'm using c++ 14. Why isn't googletest able to pick up the curl_client class object pointer? Did I initialize it correctly in CurlClientTest?
Testing code:
#include "../src/include/CurlClient.h"
#include <gtest/gtest.h>
#include <string>
class CurlClientTest : testing::Test {
public:
SimpleCURLClient::CurlClient *curl_client;
virtual void SetUp() {
curl_client = new SimpleCURLClient::CurlClient(test_url);
}
virtual void TearDown() {
delete curl_client;
}
private:
std::string test_url = "http://postman-echo.com/get?foo1=bar1&foo2=bar2";
};
TEST(CurlClientTest, CurlClientInitTest) {
std::cout << curl_client->getCurlUrl << "\n";
}
code for CurlClient.h:
#include <curl/curl.h>
#include <exception>
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#ifndef UTILS_CURLCLIENT_H
#define UTILS_CURLCLIENT_H
namespace SimpleCURLClient {
class CurlClient {
public:
CurlClient(std::string remote_url, int ip_protocol = 1, int timeout = 10,
bool follow_redirects = 1);
~CurlClient();
void setCurlUrl(std::string &new_url);
std::string getCurlUrl();
void setOption(CURLoption curl_option_command, long curl_option_value);
void setOption(CURLoption curl_option_command, std::string curl_option_value);
void setHeader(std::vector<std::string> &header_list);
std::pair<CURLcode, std::string> makeRequest();
std::pair<CURLcode, std::string> makeRequest(std::string &post_params);
std::pair<CURLcode, std::string> sendGETRequest();
std::pair<CURLcode, std::string> sendPOSTRequest(std::string &post_params);
std::pair<CURLcode, std::string> sendDELETERequest(std::string &post_params);
private:
std::string m_curl_url;
CURL *m_curl;
struct curl_slist *m_curl_header_list;
};
} // namespace SimpleCURLClient
#endif // UTILS_CURLCLIENT_H
Error:
Build FAILED.
"E:\somepath\simple_curl_cpp\build\test\simple_curl_cpp_test.vcxproj" (default target) (1) ->
(ClCompile target) ->
E:\somepath\simple_curl_cpp\test\CurlClientTest.cc(21): error C2065: 'curl_client': undeclared identifier [E:\somepath\simple_curl_cpp\build\test\simple_curl_cpp_test.vcxproj]
E:\somepath\simple_curl_cpp\test\CurlClientTest.cc(21): error C2227: left of '->getCurlUrl' must point to class/struct/union/generic type [E:\somepath\simple_curl_cpp\build\test\simple_curl_cpp_test.vcxproj]
ANSWER (GIVEN BY Chris Olsen in comments) :
We have to use TEST_F and NOT TEST. Also change CurlClientTest to public. The below code for the test works.
#include "../src/include/CurlClient.h"
#include <gtest/gtest.h>
#include <string>
class CurlClientTest : public testing::Test {
public:
SimpleCURLClient::CurlClient *curl_client;
virtual void SetUp() {
curl_client = new SimpleCURLClient::CurlClient(test_url);
}
virtual void TearDown() {
delete curl_client;
}
private:
std::string test_url = "http://postman-echo.com/get?foo1=bar1&foo2=bar2";
};
TEST_F(CurlClientTest, CurlClientInitTest) {
std::cout << curl_client->getCurlUrl() << "\n";
}
Tests using fixtures require use of the TEST_F macro. See Test Fixtures in the Google Test Primer for more info.
TEST_F(CurlClientTest, CurlClientInitTest) {
std::cout << curl_client->getCurlUrl << "\n";
}

Calling a method from one class in another class

I have this class:
boer.h
#pragma once
#include <functional>
#include <iostream>
class boer
{
private:
std::function<void(int id_)> someFun;
public:
boer();
~boer();
void setSomeFun(std::function<void(int id_)> someFun_);
void getSomeFun();
};
boer.cpp
#include "boer.h"
boer::boer() { }
boer::~boer() { }
void boer::setSomeFun(std::function<void(int id_)> someFun_)
{
someFun = someFun_;
}
void boer::getSomeFun()
{
someFun(12345);
}
And this class:
aircraft.h
#pragma once
#include <functional>
#include <iostream>
#include "boer.h"
class aircraft
{
private:
boer Boer;
public:
aircraft();
~aircraft();
void source_forSomeFun(int id_);
};
aircraft.cpp
#include "aircraft.h"
aircraft::aircraft() { }
aircraft::~aircraft() { }
void aircraft::source_forSomeFun(int lol_)
{
std::cout << "AMAZING!!!" << std::endl;
}
And I need to connect void source_forSomeFun(int id_); in aicraft with std::function<void(int id_)> someFun; in boer. How can I do this? Maybe there is another way, but i think this method is the most preferable.
int main()
{
aircraft Aircraft;
boer Boer;
Boer.setSomeFun(???); // here
Boer.getSomeFun();
int i;
std::cin >> i;
return 0;
}
Boer.setSomeFun([&](int v){aircraft.source_forSomeFun(v);});
Use a lambda.

using boost::function with instance methods

I am trying to use boost::function with instance methods using the following example
class someclass
{
public:
int DoIt(float f, std::string s1)
{
return 0;
}
int test(boost::function<int(float, std::string)> funct)
{
//Funct should be pointing to DoIt method here
funct(12,"SomeStringToPass");
}
void caller()
{
test(DoIt); //Error : 'someclass::DoIt': function call missing argument list; use '&someclass::DoIt' to create a pointer to member
}
};
Any suggestion on how I could resolve this issue ?
You should use boost::bind:
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <string>
#include <iostream>
using namespace std;
class someclass
{
public:
int DoIt(float f, std::string s1)
{
return 0;
}
int test(boost::function<int(float, std::string)> funct)
{
return funct(5.0, "hello");
}
void caller()
{
cout << test(boost::bind(&someclass::DoIt, this, _1, _2)) << endl;
}
};
int main() {
someclass s;
s.caller();
}

Boost undefined reference error with boost::bind overloaded operators

The code in question:
boost::function<bool()> isSpecialWeapon = boost::bind(&WeaponBase::GetType,this) == WeaponType::SPECIAL_WEAPON;
The error I get is something like so:
undefined reference to `boost::_bi::bind_t<bool, boost::_bi::equal,
boost::_bi::list2<boost::_bi::bind_t<WeaponType::Guns,
boost::_mfi::cmf0<WeaponType::Guns, WeaponBase>,
boost::_bi::list1<boost::_bi::value<WeaponBase*> > >,
boost::_bi::add_value<WeaponType::Guns>::type> > boost::_bi::operator==
<WeaponType::Guns, boost::_mfi::cmf0<WeaponType::Guns, WeaponBase>,
boost::_bi::list1<boost::_bi::value<WeaponBase*> >, WeaponType::Guns>
(boost::_bi::bind_t<WeaponType::Guns, boost::_mfi::cmf0<WeaponType::Guns, WeaponBase>,
boost::_bi::list1<boost::_bi::value<WeaponBase*> > > const&, WeaponType::Guns)'
If you can't get boost::bind to work as you desire, you can try Boost.Pheonix or Boost.Lamda as a workaround.
Try using boost::pheonix::bind (from Boost.Pheonix) instead of boost::bind:
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/bind/bind_member_function.hpp>
#include <boost/function.hpp>
#include <iostream>
enum WeaponType {melee, ranged, special};
class Sword
{
public:
WeaponType GetType() const {return melee;}
void test()
{
namespace bp = boost::phoenix;
boost::function<bool()> isSpecialWeapon =
bp::bind(&Sword::GetType, this) == special;
std::cout << "isSpecialWeapon() = " << isSpecialWeapon() << "\n";
}
};
int main()
{
Sword sword;
sword.test();
}
Alternatively, you also use boost::lambda::bind (from Boost.Lambda):
#include <boost/function.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <iostream>
enum WeaponType {melee, ranged, special};
class Sword
{
public:
WeaponType GetType() const {return melee;}
void test()
{
boost::function<bool()> isSpecialWeapon =
boost::lambda::bind(&Sword::GetType, this) == special;
std::cout << "isSpecialWeapon() = " << isSpecialWeapon() << "\n";
}
};
int main()
{
Sword sword;
sword.test();
}