tags:

views:

116

answers:

3

We are having a bit of trouble using find_if to search a vector of pairs for an entry in which the first element of the pair matches a particular value. To make this work, we have defined a trivial functor whose operator() takes a pair as input and compares the first entry against a string.

Unfortunately, when we actually add a call to find_if using an instance of our functor constructed using a temporary string value, the compiler produces a raft of error messages. Oddly (to me, anyway), if we replace the temporary with a string that we've created on the stack, things seem to work.

Here's what the code (including both versions) looks like:

typedef std::pair<std::string, std::string> MyPair;
typedef std::vector<MyPair> MyVector;

struct MyFunctor: std::unary_function <const MyPair&, bool>
{
  explicit MyFunctor(const std::string& val)
    : m_val(val) {}

  bool operator() (const MyPair& p)
  {
    return p.first == m_val;
  }

  const std::string m_val;
};

bool f(const char* s)
{
  MyFunctor f(std::string(s));  // ERROR
  // std::string str(s);                                                                                                  
  // MyFunctor f(str);              // OK                                                                                                    
  MyVector vec;
  MyVector::const_iterator i = std::find_if(vec.begin(), vec.end(), f);
  return i != vec.end();
}

And here's what the most interesting error message looks like:

/usr/include/c++/4.2.1/bits/stl_algo.h:260: error: conversion from ‘std::pair, std::allocator >, std::basic_string, std::allocator > >’ to non-scalar type ‘std::string’ requested

Because we have a workaround, we're mostly curious as to why the first form causes problems. I'm sure we're missing something, but we haven't been able to figure out what it is.

+6  A: 

This is the most vexing parse.

You can do:

MyFunctor f(s);

or

MyFunctor f((std::string(s)));

The original declares a function f. f takes a single argument, a pointer to a function taking an argument s and returning std::string.

Matthew Flaschen
Thanks! That clarified the situation perfectly.
Jim Wong
... or simply: `MyFunctor f( s )`. There is an implicit conversion from `const char*` to `std::string`, so there is no need to force that conversion.
David Rodríguez - dribeas
A: 

The first error at

MyFunctor f(std::string(s));

is because std::string(s) is a rvalue(temporary) and the function

explicit MyFunctor(const std::string& val)

requires a reference that cannot be taken from rvalue.

The second error message you got is because you iterating over vector<pair<string, string>> which requires a functor that takes input of type pair<string, string> but your functor accepts input of type string which leads to the compilation error.

Dani
The `MyFunctor` constructor takes a `const` reference to a string. Because of the `const`, a temporary is fine. Once the functor is constructed, `find_if` only cares what parameters operator() takes. That takes a const reference to a `MyPair`, as it should.
Matthew Flaschen
A: 
MyFunctor f = MyFunctor(s);

is more clear and works the same.

adf88
... or `MyFunctor f(s)`, which is even simpler and clearer (at least to me)
David Rodríguez - dribeas