4
Compiler: g++ 4.4.3
Boost...: 1.49.0
OS......: Ubuntu

Note: It's been 15 years since I seriously used C++, so I'm relearning and learning new things as I also try to learn Boost.

Given the following code:

1.      class Beta {
2.      public:
3.          std::string name();
4.      }
5.      
6.      class Alpha {
7.      public:
8.          Beta m_beta;
9.      }
10.     
11.     Alpha one;

For various reasons, I wanted to use boost:bind to achieve the same result as if "one.m_beta.name()" were called. I thought the following would do it:

12.     boost::function<std::string(Alpha)>
13.         b = boost::bind(
14.             &Beta::name,
15.             boost::bind(&Alpha::m_beta, _1)
16.         );
17.     cout << "NAME = " << b(one) << "\n";

But when I compile (g++ 4.4.3 on Ubuntu) I get the following error:

error: invalid conversion from ‘const Beta*’ to ‘Beta*’

After looking at the actual type definition resulting from lines 13-16, it looks like line 15 is becoming 'const Beta*', but the bind wrapping it expects 'Beta*'.

However, this DOES work:

30.     boost::function<std::string(Beta)>
31.         p1 = boost::bind(&Beta::name,_1);
32.     boost::function<Beta(Alpha)>
33.         p2 = boost::bind(&Alpha::m_beta,_1);
34.     std::cout << "NAME = " << p1(p2(one)) << "\n";

But I really don't want to carry around a lot of intermediate variables. It did make me think that there must be some way to get the first version to work as well. I've already tried the following as replacements for line 15, but they all give out one or another error at compilation time too.

50. (boost::function<Beta&(Alpha)>)(boost::bind(&Alpha::m_beta,_1))
51. (boost::function<Beta(Alpha)>)(boost::bind(&Alpha::m_beta,_1))
52. (boost::function<Beta*(Alpha)>)(boost::bind(&Alpha::m_beta,_1))
53. boost::protect(boost::bind(&Alpha::m_beta,_1))
54. boost::ref(boost::bind(&Alpha::m_beta,_1))
55. const_cast<Beta*>(boost::bind(&Alpha::m_beta,_1))
56. const_cast<boost::function<Beta(Alpha) > >(boost::bind(&Alpha::m_beta,_1))
57. const_cast<boost::function<Beta*(Alpha) > >(boost::bind(&Alpha::m_beta,_1))

What am I missing?

5
  • Well one thing to note is that bind is now standard (in <functional>). There's no need to use Boost anymore, since even GCC 4.4 supports it. Commented Aug 18, 2012 at 2:11
  • 1
    I'd almost guarantee that the actual issue is a (symptom of the) failure of perfect fowarding in C++99/03. Somewhere a Beta is being accepted as a Beta const&. You might try compiling with --std=c++0x and using std::bind; that might have been implemented to do perfect forwarding. Commented Aug 18, 2012 at 2:34
  • Note that for (what I assume to be) your synthetic example it would very likely be customary to declare Beta::name as std::string name() const;. This would in all likeliness avoid the error (although the question still is very relevant in spirit). Commented Aug 18, 2012 at 3:23
  • Many thanks to all of you! Twansbury's answer does exactly what I needed, but I'm going to give the other suggestions a try as well. Commented Aug 18, 2012 at 15:04
  • @LucDanton Unfortunately, Alpha and Beta are stand-ins for two classes in a third party library that while I have source, I'm not supposed to modify. Commented Aug 19, 2012 at 14:34

1 Answer 1

5

Explicitly specify a Beta& return type for the nested boost::bind:

boost::function< std::string( Alpha ) > b =
  boost::bind(
    &Beta::name,
    boost::bind< Beta& >( &Alpha::m_beta, _1 ) );

The reason the const Beta* and Beta* conversion errors are occurring is the result of boost::bind having the same behavior as boost::mem_fn, which states:

mem_fn also supports pointers to data members by treating them as functions taking no arguments and returning a (const) reference to the member.`

Thus, the nested-bind is returning a const Beta&, which is an invalid instance to invoke the non-const name() member function on Beta.

Sign up to request clarification or add additional context in comments.

3 Comments

With Boost 1.50 there are also some pains when passing the result of boost::bind to boost::function. If the signature of b is changed to std::string(Alpha&) this compiles however.
Finally, std::bind (even in tandem with std::function) does not appear to exhibit this problem. (Which is conforming to the specification TTBMK.)
Many thanks to all of you! Twansbury's answer does exactly what I needed, but I'm going to give the other suggestions a try as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.