binding to member variables - c++

The following example from boost bind does not work for me:
#include <boost/bind.hpp>
struct A
{
int data;
};
int main()
{
A a;
boost::bind(&A::data, _1)(a) = 1;
}
error: assignment of read-only location 'boost::bind [with A1 = boost::arg<1>, M = int, T = A](&A::data, (<unnamed>::_1, boost::arg<1>())).boost::_bi::bind_t<R, F, L>::operator() [with A1 = A, R = const int&, F = boost::_mfi::dm<int, A>, L = boost::_bi::list1<boost::arg<1> >](((A&)(& a)))'
Am I doing anything wrong? The compiler is g++ 4.4.0

The result type of that bind expression is int (or rather const int&). I think you can override the return type:
boost::bind<int&>(&A::data, _1)(a) = 1;

UncleBens' solution is fine but I thought I'd add that if you use Boost.Lambda the problem disappears:
#include <boost/lambda/bind.hpp>
struct A {
int data;
};
int main() {
namespace bll = boost::lambda;
A a;
bll::bind(&A::data, bll::_1)(a) = 1;
}
And so it does if you use boost::mem_fn:
#include <boost/mem_fn.hpp>
struct A {
int data;
};
int main() {
boost::mem_fn(&A::data)(a) = 1;
}

I'm not sure what you want to do, but does Boost.Bind really overload the assignment operator? If you'd like to assign the value 1 to a.data using the returned function object I think you need to do something like this (also note that "a" needs to be bound by reference):
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <cassert>
void foo()
{
A a;
boost::bind(&A::data, _1)(boost::ref(a), 1);
assert(a.data == 1);
}
If you need to use the assignment operator I think that using Boost.Lambda or Boost.Phoenix would be a better choice.

Related

Is it possible to safely make a tuple of lvalue references for an aggregate object using fewer than three declarations?

I want to support some method, preferably named tie(), on my aggregate classes to allow callers to leverage various functionality involving std::tuple objects. The functionality is not limited to what is provided in the standard library.
My best attempt at a safe and fully featured implementation requires three overloads, as shown below.
#include <string>
#include <tuple>
#include <iostream>
struct Foo {
std::string s1;
std::string s2;
auto tie() const & { return std::tie(s1, s2); }
auto tie() & { return std::tie(s1, s2); }
// auto tie() && = delete;
};
int main()
{
auto refs = Foo{"this is a long string", ""}.tie();
std::cout << std::get<0>(refs); // <- prints garbage
return 0;
}
I rejected std::make_tuple due to performance concerns. Is there a better way to achieve the desired outcome?
The following technique achieves the desired outcome.
#include <string>
#include <tuple>
#include <iostream>
struct Foo {
std::string s1;
std::string s2;
friend auto tie(auto& foo) { return std::tie(foo.s1, foo.s2); }
};
int main()
{
auto foo = Foo{"", ""};
auto refs = tie(foo);
static_assert(std::tuple_size_v<decltype(refs)> == 2);
auto stdrefs = std::tie(foo);
static_assert(std::tuple_size_v<decltype(stdrefs)> == 1);
tie(Foo{"",""}); // cannot bind non-const lvalue reference error
return 0;
}

std::function Error : error: static assertion failed: Wrong number of arguments for pointer-to-member?

I have a tricky problem and I'm working on it for several hours but can't find a cause and solution of it. Hope someone help me.
I have to demonstrate function being called inside another function( pls see the comment in seminar.cpp)
Below are the files ( I have separated it into header and code files)
main.cpp
#include <iostream>
#include <functional>
#include "seminar.h"
int main()
{
Tom::Car::Car car;
Nor::Driving drivingnow;
std::vector<uint8_t> X = car.road(drivingnow);
for(int i = 0 ; i < X.size() ; i++){
std::cout<<unsigned(X[i])<<" ";
}
return 0;
}
seminar.h
#pragma once
#include "dist.h"
#include <vector>
#include <bits/stdc++.h>
namespace Tom
{
namespace Car
{
class Car
{
public:
std::vector<uint8_t> road(Nor::Driving &driving);
};
} // namespace Car
} // namespace Tom
seminar.cpp
#include "seminar.h"
#include <algorithm>
#include <functional>
namespace Tom
{
namespace Car
{
std::vector<uint8_t> drive(Nor::Range &range)
{
std::vector<uint8_t> s;
s.push_back(range.z);
s.push_back(range.zz);
return s;
}
template <typename T, typename B, typename L>
std::vector<uint8_t> Content(T Sec, B Byte, L Func)
{
Nor::Range Rom;
std::vector<uint8_t> z = Func(Rom);
return z;
}
std::vector<uint8_t> Car::road(Nor::Driving &driving)
{
std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;
return Content(driving, 1, Func); // passing drive function into content
}
} // namespace Car
} // namespace Tom
dist.h
namespace Nor
{
class Driving{
public:
int x = 1;
};
class Range{
public:
int z = 50;
int zz = 100;
};
}
The above code and file structure works correctly and give me the correct expected output ie 50 100
Live here
Now I want to do more separation ie I want the implementation of drive function to move in another file ie in type.cpp
type.cpp
#include <algorithm>
#include "seminar.h"
#include <functional>
namespace Tom
{
namespace Car
{
std::vector<uint8_t> Car::drive(Nor::Range &range)
{
std::vector<uint8_t> s;
s.push_back(range.z);
return s;
}
} // namespace Car
} // namespace Tom
seminar.h
#pragma once
#include "dist.h"
#include <vector>
#include <bits/stdc++.h>
namespace Tom
{
namespace Car
{
class Car
{
public:
std::vector<uint8_t> road(Nor::Driving &driving);
std::vector<uint8_t> drive(Nor::Range &range);
};
} // namespace Car
} // namespace Tom
seminar.cpp
#include "seminar.h"
#include <algorithm>
#include <functional>
namespace Tom
{
namespace Car
{
template <typename T, typename B, typename L>
std::vector<uint8_t> Content(T Sec, B Byte, L Func)
{
Nor::Range Rom;
std::vector<uint8_t> z = Func(Rom);
return z;
}
std::vector<uint8_t> Car::road(Nor::Driving &driving)
{
std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;
return Content(driving, 1, Func);
}
} // namespace Car
} // namespace Tom
Live here
After doing this I am getting an below error:
seminar.cpp: In member function ‘std::vector<unsigned char> Tom::Car::Car::road(Nor::Driving&)’:
seminar.cpp:22:71: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&Tom::Car::Car::drive’ [-fpermissive]
22 | std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;
| ^~~~~
seminar.cpp:22:71: error: conversion from ‘std::vector (Tom::Car::Car::*)(Nor::Range&)’ to non-scalar type ‘std::function(Nor::Range&)>’ requested
Taking reference from this answer
I tried this way :
std::function<std::vector<uint8_t>(Nor::Range)> f = std::bind(&Car::drive, this);
And Got this error:
/usr/include/c++/9/functional:775:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
774 | static_assert(_Varargs::value
| ~~~~~
775 | ? sizeof...(_BoundArgs) >= _Arity::value + 1
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
776 | : sizeof...(_BoundArgs) == _Arity::value + 1,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
seminar.cpp: In member function ‘std::vector<unsigned char> Tom::Car::Car::road(Nor::Driving&)’:
seminar.cpp:23:73: error: conversion from ‘std::_Bind_helper (Tom::Car::Car::*)(Nor::Range&), Tom::Car::Car*>::type’ {aka ‘std::_Bind (Tom::Car::Car::*(Tom::Car::Car*))(Nor::Range&)>’} to non-scalar type ‘std::function(Nor::Range)>’ requested
23 | std::function<std::vector<uint8_t>(Nor::Range)> f = std::bind(&Car::drive, this);
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~
seminar.cpp:25:40: error: ‘Func’ was not declared in this scope
25 | return Content(driving, 1, Func);
See here live
I don't know correctly what I am doing wrong in moving the implementation of drive function can someone please help with implementing the corrrect way.
Note:: I'm fine if the solution uses another way to pass the function ie by not using std::function . Thanks
In seminar.cpp, here:
std::function<std::vector<uint8_t>(Nor::Range &)> Func = &drive;
drive is a member function. It needs the this pointer to be called.
You can easily solve this by wrapping it in a lambda:
std::function<std::vector<uint8_t>(Nor::Range &)> Func = [this](Nor::Range & r) {
return this->drive(r);
};
If you prefer the std::bind method that you tried, you need a placeholder for the Nor::Range& parameter:
std::function<std::vector<uint8_t>(Nor::Range &)> Func = std::bind(&Car::drive, this, std::placeholders::_1);
Also, you really don't need the std::function at all since it's a local variable that you immediately pass to another function, so just use auto instead (or pass it directly without an intermediate variable):
auto Func = [this](Nor::Range & r) {
return this->drive(r);
};
Non-static member function pointers should be initialized in this way:
return_type (class_name::*pointer_name)(argument_types ...) = &class_name::function_name;
They should be called in this way:
(instance_name.*pointer_name)(arguments ...);
Such pointers can be assigned to std::function objects, which is a bit complicated. You should pay attention that this is an implicit argument in a member function, so the pointer type of the class should be explicitly declared as an argument in the template of the std::function object in such an assignment. For example,
std::function<std::vector<uint8_t>(Car *, Nor::Range &)> Func = &Car::drive;
You also mentioned the std::bind function. In this case, you should use std::placeholders to hold the place for undetermined arguments. Pay attention that the template of the std::function object should only contain undetermined arguments.
std::function<std::vector<uint8_t>(Nor::Range &)> Func = std::bind(&Car::drive, this, std::placeholders::_1);
You may try auto:
auto Func = std::bind(&Car::drive, this, std::placeholders::_1);
The std::placeholders::_1 allows the argument Nor::Range &range to be passed to the function Car::drive later. The implicit argument this should also be explicitly used in the std::bind function.

Storing pointer to functions in a map

Can anyone explain why this piece of code is generating the error as shown below. I am trying to store pointer to function in a map. The code would work fine if I keep everything in main() function. Also I would appreciate it if someone shows how to fix it.
#include <boost/variant.hpp>
#include <map>
#include <iostream>
#include <map>
using namespace boost;
class obj {
public:
int num1;
int num2;
std::string s1;
std::string s2;
};
typedef boost::variant<int, float, double, std::string> MultiType;
typedef MultiType(*FnPtr)(obj);
class c {
public:
MultiType add(obj o);
std::map<std::string, FnPtr> metricToFuncMap = { { "i", add } };
};
MultiType c::add(obj o) {
{ MultiType x; x = o.num1 + o.num2; return x; }
}
int main() {
obj o;
//add
MultiType d;
d = 1;
o.num1 = 1;
o.num2 = 2;
//concat
o.s1 = "hello";
o.s2 = "world";
c c;
MultiType x = c.metricToFuncMap["i"](o);
std::cout << get<int>(x);
return 0;
}
Error:
E0289 no instance of constructor "std::map<_Kty, _Ty, _Pr, _Alloc>::map [with _Kty=std::string, _Ty=FnPtr, _Pr=std::less<std::string>, _Alloc=std::allocator<std::pair<const std::string, FnPtr>>]" matches the argument list
Here's a fairly minimal example.
#include <iostream>
#include <functional>
#include <map>
class Foo {
public:
Foo() {}
};
typedef std::function<std::string (const Foo &)> MyFunction;
typedef std::map<std::string, MyFunction> MyMap;
int main(int, char **) {
Foo foo;
MyFunction f = [](const Foo &) { return "Hello"; };
MyMap myMap { {"x", f} };
MyFunction blah = myMap["x"];
std::cout << "Got: " << blah(foo) << "\n";
}
Compile and run:
$ g++ --std=c++17 Blah.cpp -o Blah && Blah
Got: Hello
The advantage of using std::function is that while there's a little overhead, it's far more powerful. You can (as I have) used lambdas. Your lambdas can capture this, meaning you can call non-static member methods. You can also use std::bind(), if you prefer, although I don't care for the syntax and will usually use a lambda instead.

Method pointer with boost::bind and map

Is there a nicer way of doing this
auto commodityOneLeg = boost::bind(&VegaFactory::load_commodity_one_leg,this,conn,_1);
std::map<std::string,decltype(commodityOneLeg)> methods;
methods.insert(std::make_pair("COMMODITYONELEG",commodityOneLeg));
methods.insert(std::make_pair("FXOPTION",boost::bind(&VegaFactory::load_fx_index,this,conn,_1)));
methods.insert(std::make_pair("FXBARROPT",boost::bind(&VegaFactory::load_fx_bar_opt,this,conn,_1)));
methods.insert(std::make_pair("COMMODITYINDEX",boost::bind(&VegaFactory::load_fx_index,this,conn,_1)));
auto f = methods.find(trade_table);
if(f != methods.end()) {
fx_opt = (f->second)(t_id);
}
Is there a way of declaring the type of std:map<> without having to declare a mapping first on the previous line? I guess I mean aesthetically - Code should look neat right?
Is there a cleaner/simpler way to do this c++ string switch statement overall when the input is a 'trade type' string.
Edit
To clarify further. I can manually write out the type of the boost:bind type but that seems excessive. And this is probably a really good example of where auto and decltype can be used to simplify the code.
However having to declare one entry in the map one way and the others in a different way just looks wrong; so that's what I want to address
IMHO using Boost.Signals2 is a more clear way. There is also the Boost.Signals library but it is deprecated starting from Boost 1.54. The following code demonstrates it. I think something similar is possible to implement using the Boost.Function library too.
#include <boost/signals2.hpp>
#include <map>
#include <string>
typedef boost::signals2::signal<bool (int)> CSignal;
typedef CSignal::slot_type CSignalSlotType;
typedef std::map<std::string, CSignalSlotType> CMethodMap;
bool Func1(int a, int b) {
return a == b;
}
bool Func2(int a, int b) {
return a < b;
}
int main(int, char *[]) {
CMethodMap methods;
methods.insert(std::make_pair("Func1", boost::bind(&Func1, 1, _1)));
methods.insert(std::make_pair("Func2", boost::bind(&Func2, 2, _1)));
auto it = methods.find("Func1");
if(it != methods.end()) {
CSignal signal;
signal.connect(it->second);
auto rt = signal(2);
if (rt) {
const bool result = *rt;
}
}
return 0;
}
Here is a sample code using the Boost.Function. It looks even simpler but I used to use the Signals2 library.
#include <map>
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
typedef boost::function<bool (int)> CFunction;
typedef std::map<std::string, CFunction> CMethodMap;
bool Func1(int a, int b) {
return a == b;
}
bool Func2(int a, int b) {
return a < b;
}
int main(int, char *[]) {
CMethodMap methods;
methods.insert(std::make_pair("Func1", boost::bind(&Func1, 1, _1)));
methods.insert(std::make_pair("Func2", boost::bind(&Func2, 2, _1)));
auto it = methods.find("Func1");
if(it != methods.end()) {
auto &f = it->second;
const bool result = f(2);
}
return 0;
}

C++ - binding function

I have some (library API, so I can't change the function prototype) function which is written the following way:
void FreeContext(Context c);
Now, at some moment of my execution I have Context* local_context; variable and this is also not a subject to change.
I wish to use boost::bind with FreeContext function, but I need to retrieve Context from local variable Context*.
If I write my code the following way, the compiler says it's "illegal indirection":
boost::bind(::FreeContext, *_1);
I managed to solve this problem the following way:
template <typename T> T retranslate_parameter(T* t) {
return *t;
}
boost::bind(::FreeContext,
boost::bind(retranslate_parameter<Context>, _1));
But this solution doesn't seem really good to me. Any ideas on how to solve this using something like *_1. Maybe writing a small lambda function?
You could use Boost.Lambda which have overloaded the * operator for _n.
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <algorithm>
#include <cstdio>
typedef int Context;
void FreeContext(Context c) {
printf("%d\n", c);
}
int main() {
using boost::lambda::bind;
using boost::lambda::_1;
Context x = 5;
Context y = 6;
Context* p[] = {&x, &y};
std::for_each(p, p+2, bind(FreeContext, *_1));
return 0;
}
Use either Boost.Lambda or Boost.Phoenix to have a working operator* on a placeholder.
You can also place the Context pointer in a shared_ptr with a custom deleter:
#include <memory> // shared_ptr
typedef int Context;
void FreeContext(Context c)
{
printf("%d\n", c);
}
int main()
{
Context x = 5;
Context* local_context = &x;
std::shared_ptr<Context> context(local_context,
[](Context* c) { FreeContext(*c); });
}
Not sure this is relevant though. Good luck!