Error C2668 in bind while porting from VS2008 to VS2013

254 views Asked by At

I'm trying to port my code from VS2008 to VS2013 and I'm getting some errors with std::bind. The errors say error C2668: 'bind' : ambiguous call to overloaded function. Here's some code:

// Relevant prototypes:
class CLineaPlanta:public SomeBase { /*...*/ };
int SomeBase::TipoLinea()const;
void SomeBase::TipoLinea(int val);

// function paramater: const std::shared_ptr<CLineaPlanta>& lineasBuscar
// function parameter: int tipoLinea;

std::shared_ptr<CLineaPlanta> lineas;
std::remove_copy_if(lineasBuscar.begin(), lineasBuscar.end(),
std::back_inserter(lineas), 
        bind(std::not_equal_to<int>(), bind(&CLineaPlanta::TipoLinea, _1), tipoLinea));

This code worked in Visual Studio 2008, but gives the mentioned error in Visual Studio 2013.

Obviously, the compiler's having a hard time figuring out which version of TipoLinea() I'm trying to call. If I rename the getter version to getTipoLinea, the error goes away.

Just in case it is relevant, SomeBase is non-abstract and derives from CObject (not really sure why) and from an interface not related to this part of the code.

Can anyone explain why VS2008 doesn't have any problem with this and how to prevent it (other than by renaming the function, of course)?

1

There are 1 answers

1
Sebastian Redl On BEST ANSWER

I have no idea why this code ever worked in VS2008. It was probably a consequence of 2008's bind being implemented as a macro-based variadics emulation where bind had several overloads for each number of arguments being passed, one of them expecting the first argument to be a pointer to member function with the same number of arguments. This would allow the compiler to disambiguate because you pass one bound argument to bind, so it knows the function argument must have one parameter.

In VS2013, true variadics are used, but this probably means that the type of the first argument is more generic and so the compiler can no longer disambiguate. To make this compile, you need to explicitly cast the member pointer:

std::remove_copy_if(lineasBuscar.begin(), lineasBuscar.end(),
    std::back_inserter(lineas), 
    bind(std::not_equal_to<int>(),
         bind(static_cast<int (SomeBase::*)() const>(&CLineaPlanta::TipoLinea),
              _1),
             tipoLinea));

But as Neil Kirk said, rewriting to a lambda is easier:

std::remove_copy_if(lineasBuscar.begin(), lineasBuscar.end(),
    std::back_inserter(lineas),
    [tipoLinea](const std::shared_ptr<CLineaPlanta>& linea) {
        return linea->TipoLinea() != tipoLinea;
    });