Bind to a member's class method.

Hi, I am rather beginner at boost - I am trying to achieve functionality similiar to property getter/setter from managed languages like C#. I have written the following code: #include "boost\lambda\bind.hpp" #include "boost\variant.hpp" #include "boost\optional.hpp" #include <iostream> #include <map> class Test { public: boost::optional<boost::variant<int, std::string>> m_value; }; int _tmain(int argc, _TCHAR* argv[]) { Test t1, t2; auto b1 = boost::lambda::bind(&Test::m_value, boost::lambda::_1); auto b2 = boost::lambda::bind(Test::m_value::get_value_or, boost::lambda::_1, "empty"); b1(t1) = "Test value"; std::cout << b2(t1); // "Test value" std::cout << b2(t2); // Should be "empty" return 0; } Unfortunately the compilers says: boost_tests.cpp(32): error C3083: 'm_value': the symbol to the left of a '::' must be a type boost_tests.cpp(32): error C2039: 'get_value_or' : is not a member of 'Test' boost_tests.cpp(22) : see declaration of 'Test' boost_tests.cpp(32): error C2065: 'get_value_or' : undeclared identifier boost_tests.cpp(32): fatal error C1903: unable to recover from previous error(s); stopping compilation I'd like to create a bind to Test::m_value.get_value_or() function with the first parameter set to "empty" - any ideas how to achieve that? Regards, Konrad.

On 03/21/2014 12:00 PM, Konrad Rybacki wrote:
class Test { public: boost::optional<boost::variant<int, std::string>> m_value; };
Seems to me that you need to refer to the type of the member variable, not the actual instance, so: class Test { public: typedef boost::optional<boost::variant<int, std::string>> Value; Value m_value; }; auto b2 = boost::lambda::bind(Test::Value::get_value_or, boost::lambda::_1, "empty"); WBR, Adam Romanek

Hi, Unfortunately, with the code you have proposed I get the following error: boost_tests.cpp(33): error C3867: 'boost::optional<T>::get_value_or': function call missing argument list; use '&boost::optional<T>::get_value_or' to create a pointer to member with [ T=boost::variant<int,std::string> ] boost_tests.cpp(33): error C2780: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::action<10,boost::lambda::function_action<10,T>>,detail::bind_tuple_mapper<const Arg1,const Arg2,const Arg3,const Arg4,const Arg5,const Arg6,const Arg7,const Arg8,const Arg9,const Arg10>::type>> boost::lambda::bind(const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &,const Arg6 &,const Arg7 &,const Arg8 &,const Arg9 &,const Arg10 &)' : expects 10 arguments - 3 provided f:\boost_1_55_0\boost\lambda\detail\bind_functions.hpp(1743) : see declaration of 'boost::lambda::bind' boost_tests.cpp(33): error C2780: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::action<Arity,Act>,detail::bind_tuple_mapper<const Arg1,const Arg2,const Arg3,const Arg4,const Arg5,const Arg6,const Arg7,const Arg8,const Arg9,const Arg10>::type>> boost::lambda::bind(const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &,const Arg6 &,const Arg7 &,const Arg8 &,const Arg9 &,const Arg10 &)' : expects 10 arguments - 3 provided with [ Arity=10, Act=boost::lambda::function_action<10> ] f:\boost_1_55_0\boost\lambda\detail\bind_functions.hpp(1710) : see declaration of 'boost::lambda::bind' boost_tests.cpp(33): error C2780: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::action<10,boost::lambda::function_action<10,T>>,detail::bind_tuple_mapper<Result(__cdecl &)(Par1,Par2,Par3,Par4,Par5,Par6,Par7,Par8,Par9),const Arg2,const Arg3,const Arg4,const Arg5,const Arg6,const Arg7,const Arg8,const Arg9,const Arg10>::type>> boost::lambda::bind(Result (__cdecl &)(Par1,Par2,Par3,Par4,Par5,Par6,Par7,Par8,Par9),const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &,const Arg6 &,const Arg7 &,const Arg8 &,const Arg9 &,const Arg10 &)' : expects 10 arguments - 3 provided f:\boost_1_55_0\boost\lambda\detail\bind_functions.hpp(1673) : see declaration of 'boost::lambda::bind' boost_tests.cpp(33): error C2780: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::action<9,boost::lambda::function_action<9,T>>,detail::bind_tuple_mapper<const Arg1,const Arg2,const Arg3,const Arg4,const Arg5,const Arg6,const Arg7,const Arg8,const Arg9>::type>> boost::lambda::bind(const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &,const Arg6 &,const Arg7 &,const Arg8 &,const Arg9 &)' : expects 9 arguments - 3 provided f:\boost_1_55_0\boost\lambda\detail\bind_functions.hpp(1526) : see declaration of 'boost::lambda::bind' boost_tests.cpp(33): error C2780: 'const boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::action<Arity,Act>,detail::bind_tuple_mapper<const Arg1,const Arg2,const Arg3,const Arg4,const Arg5,const Arg6,const Arg7,const Arg8,const Arg9>::type>> boost::lambda::bind(const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &,const Arg6 &,const Arg7 &,const Arg8 &,const Arg9 &)' : expects 9 arguments - 3 provided And so on... Regards, Konrad.

On 03/21/2014 12:31 PM, Konrad Rybacki wrote:
Unfortunately, with the code you have proposed I get the following error:
...
And so on...
Sorry, I didn't test it, just assumed this was the source of the problem. After some struggling I finally managed to fix the code, however the solution isn't perfect. #include <boost/lambda/bind.hpp> #include <boost/variant.hpp> #include <boost/optional.hpp> #include <iostream> #include <map> class Test { public: typedef boost::optional<boost::variant<int, std::string>> Value; typedef Value::reference_const_type (Value::*GetValueOrConstFn)(Value::reference_const_type) const; Value m_value; }; int main(int argc, const char* argv[]) { Test t1, t2; std::string empty("empty"); auto b1 = boost::lambda::bind(&Test::m_value, boost::lambda::_1); // static_cast is based on http://stackoverflow.com/a/2862235/1776942 auto b2 = boost::lambda::bind(static_cast<Test::GetValueOrConstFn>(&Test::Value::get_value_or), boost::lambda::_1, empty); b1(t1) = "Test value"; std::cout << b2(b1(t1)) << '\n'; // "Test value" std::cout << b2(b1(t2)) << '\n'; // Should be "empty" return 0; } The first problem was that boost::lambda::bind can't infer the return type out of overloaded member function (see [1] for a related SO question). The second problem was that b2 functor was passed an invalid argument. The argument passed was of Test type, not Test::Value, as expected by Test::Value::get_value_or(). Note that you could replace boost::lambda::bind with boost::bind to get rid of this ugly static_cast: auto b2 = boost::bind<Test::Value::reference_const_type>(&Test::Value::get_value_or, _1, empty); This works too and looks much better. P.S. I compiled it using clang on Ubuntu Linux so I had to change some minor bits in the code. WBR, Adam Romanek
participants (2)
-
Adam Romanek
-
Konrad Rybacki