Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behavior change in boost::bind / boost::function since 1.55

Tags:

c++

boost

I was trying to compile a project that was written against Boost 1.55 against newer Boost 1.63, and I am running into a really strange error related to bind/function. Here's the complete, simplified test case:

#include <boost/bind.hpp>
#include <boost/function.hpp>

template < typename Arg1 = int, typename Arg2 = int, typename Arg3 = int >
class foo
{
public:
  using function_t = boost::function3< void, Arg1, Arg2, Arg3 >;

  void set_function( function_t f )
  {
    func_ = f;
  }

private:
  function_t func_;
};

class bar
{
public:
  bar()
  {
    foo_.set_function( boost::bind( &bar::func, this, _1, _2 ) );
  }

private:
  void func( int const&, int& ) {}

  foo< int, int > foo_;
};

int main()
{
  bar x;
  return 0;
}

...and some select snippets of the errors I'm getting:

/usr/include/boost/bind/bind.hpp:398:35: error: no match for call to ‘(boost::_mfi::mf2<void, bar, const int&, int&>) (bar*&, int, int)’
/usr/include/boost/bind/mem_fn_template.hpp:278:7: note: candidate: R boost::_mfi::mf2<R, T, A1, A2>::operator()(T*, A1, A2) const [with R = void; T = bar; A1 = const int&; A2 = int&] <near match>
/usr/include/boost/bind/mem_fn_template.hpp:278:7: note:   conversion of argument 3 would be ill-formed:
/usr/include/boost/bind/bind.hpp:398:35: error: cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
/usr/include/boost/bind/mem_fn_template.hpp:283:25: note: candidate: template<class U> R boost::_mfi::mf2<R, T, A1, A2>::operator()(U&, A1, A2) const [with U = U; R = void; T = bar; A1 = const int&; A2 = int&]
/usr/include/boost/bind/mem_fn_template.hpp:283:25: note:   template argument deduction/substitution failed:
/usr/include/boost/bind/bind.hpp:398:35: note:   cannot convert ‘(& a)->boost::_bi::rrlist3<int, int, int>::operator[](boost::_bi::storage3<boost::_bi::value<bar*>, boost::arg<1>, boost::arg<2> >::a3_)’ (type ‘int’) to type ‘int&’
/usr/include/boost/bind/mem_fn_template.hpp:291:25: note: candidate: template<class U> R boost::_mfi::mf2<R, T, A1, A2>::operator()(const U&, A1, A2) const [with U = U; R = void; T = bar; A1 = const int&; A2 = int&]
/usr/include/boost/bind/mem_fn_template.hpp:291:25: note:   template argument deduction/substitution failed:
/usr/include/boost/bind/bind.hpp:398:35: note:   cannot convert ‘(& a)->boost::_bi::rrlist3<int, int, int>::operator[](boost::_bi::storage3<boost::_bi::value<bar*>, boost::arg<1>, boost::arg<2> >::a3_)’ (type ‘int’) to type ‘int&’
/usr/include/boost/bind/mem_fn_template.hpp:299:7: note: candidate: R boost::_mfi::mf2<R, T, A1, A2>::operator()(T&, A1, A2) const [with R = void; T = bar; A1 = const int&; A2 = int&]
/usr/include/boost/bind/mem_fn_template.hpp:299:7: note:   no known conversion for argument 1 from ‘bar*’ to ‘bar&’

If I try on another machine that has Boost 1.55, it compiles just fine. (The project also compiled okay on the same machine when pointed to a build of Boost 1.55, so the problem does not seem to be the compiler.) So, apparently something has changed in Boost that is newly causing this to fail.

I didn't write this code, not am I intimately familiar with the guts of boost::function and boost::bind. If someone could explain to me why this is breaking with newer Boost, and either a) how to fix it, or b) why the above code is broken, it would be much appreciated!

like image 785
Matthew Avatar asked Aug 07 '17 14:08

Matthew


1 Answers

The problem is that boost::function has become stricter in matching the function signature (I think to more closely match the behavior of std::function). Your function is declared to be boost::function3< void, Arg1, Arg2, Arg3 >, however, the function you're binding to it takes int const& and int&.

There are a couple of ways to fix this. You could:

  1. Change the instantion of foo<int, int> in bar to be foo<int const&, int&>.
  2. Change the declaration of function_t to be boost::function3<void, Arg1, Arg2 const&, Arg3&>.
  3. Change the signature of bar::func to accept its arguments by value.
like image 96
Nathan Ernst Avatar answered Oct 26 '22 23:10

Nathan Ernst