views:

422

answers:

3

I have a generic function:

void ImageAlbum::ExpressButtonPressed(
    boost::function<
     void (
      thumb::PhotoPrintThumbnail*,
      thumb::PhotoPrintFormat,
      thumb::PhotoPrintQuantity
     )
    > memberToCall
) {
    ...

    BOOST_FOREACH(thumb::PhotoPrintThumbnail *pThumbnail, m_thumbs.GetSelected()) {
 memberToCall(
      pThumbnail,
      m_expressSel.GetSelectedFormat(),
      m_expressSel.GetSelectedQuantity()
     );
    }

    ...
}

I can successfully call:

ExpressButtonPressed(boost::bind(&thumb::PhotoPrintThumbnail::AddQuantity, _1, _2, _3));

Then, instead of adding a quantity of a certain format to a thumbnail, I need to replace them all with a single format. More precise, with a list of 1 element, like that:

ExpressButtonPressed(
    boost::lambda::bind(
     &thumb::PhotoPrintThumbnail::SetFormats,
     _1,
     boost::lambda::bind(
      boost::lambda::constructor<thumb::PhotoPrintThumbnail::LoadedFormats>(),
      1,
      boost::lambda::bind(
       boost::lambda::constructor<thumb::PhotoPrintThumbnail::LoadedFormat>(),
       _2,
       _3
      )
     )
    )
);

Which results in "boost/lambda/detail/actions.hpp(96) : error C2665: 'boost::lambda::function_adaptor::apply' : none of the 2 overloads could convert all the argument types".

What am I doing wrong here?

BTW

class PhotoPrintThumbnail {
public:
...
    typedef std::pair<PhotoPrintFormat, PhotoPrintQuantity> LoadedFormat;
    typedef std::list<LoadedFormat> LoadedFormats;
    void SetFormats(const LoadedFormats &formats);
A: 

Not sure what version of Boost or what compiler are you using. With boost 1.37 and VS2005 i can get the same error. I suspect it may be that an error at the heart of the template expansion is causing a SFINAE issue.

For instance taking the innermost expression out:

boost::function<
    PhotoPrintThumbnail::LoadedFormat (
            PhotoPrintFormat,
            PhotoPrintQuantity
    )
> func = boost::lambda::bind
                ( boost::lambda::constructor<PhotoPrintThumbnail::LoadedFormat>()
                , _1
                , _2
                );

That looks ok to me yet also fails, albeit with a :

std::pair<_Ty1,_Ty2>::pair' : none of the 3 overloads could convert all the argument types

error.

Of course you could just use:

void func
( PhotoPrintThumbnail* ppt
, const PhotoPrintFormat& ppf
, const PhotoPrintQuantity& ppq
)
{
    ppt->SetFormats (PhotoPrintThumbnail::LoadedFormats (1, PhotoPrintThumbnail::LoadedFormat (ppf, ppq)));
}

ExpressButtonPressed (func);

which is clearer and compiles.

jon hanson
A: 

I think at the first bind, you should bind the constructed object (resulted from the second bind) as first parameter of the method (it should be the address of the constructed object):

ExpressButtonPressed(
    boost::lambda::bind(
        &thumb::PhotoPrintThumbnail::SetFormats,
        boost::lambda::bind(
                boost::lambda::constructor<thumb::PhotoPrintThumbnail::LoadedFormats>(),
                1,
                boost::lambda::bind(
                        boost::lambda::constructor<thumb::PhotoPrintThumbnail::LoadedFormat>(),
                        _2,
                        _3
                )
        ),
        _1
    )
);

I didn't try to compile the code. One other possible issue is that the second bind functor might return the constructed object by value, and the first bind requires a pointer to object (as this pointer), so you still need a pointer as first bound parameter for SetFormats.

Cătălin Pitiș
+3  A: 

Do you happen to #include boost/bind.hpp in your lambda-using code? This would cause unqualified use of the placeholders (_1, _2, etc) to resolve to those defined by Boost.Bind, and these don't mix well with Boost.Lambda.

Rewriting your code to explicitly use boost::lambda::_[1,2,3] instead of the unqualified names compiles fine on my VC 7.1 setup.

Éric Malenfant