views:

154

answers:

3

I'm having compiler errors, and I'm not sure why. What am I doing wrong here:

Hangman.cpp:

set<char> Hangman::incorrectGuesses()
{
     // Hangman line 103
    return Utils::findAll_if<char>(guesses.begin(), guesses.end(), &Hangman::isIncorrectGuess);
}

bool Hangman::isIncorrectGuess(char c)
{
    return correctAnswer.find(c) == string::npos;
}

Utils.h:

namespace Utils
{
    void PrintLine(const string& line, int tabLevel = 0);
    string getTabs(int tabLevel);

    template<class result_t, class Predicate>
    std::set<result_t> findAll_if(typename std::set<result_t>::iterator begin, typename std::set<result_t>::iterator end, Predicate pred)
    {
        std::set<result_t> result;
              // utils line 16
        return detail::findAll_if_rec<result_t>(begin, end, pred, result);
    }
}

namespace detail
{
    template<class result_t, class Predicate>
    std::set<result_t> findAll_if_rec(typename std::set<result_t>::iterator begin, typename std::set<result_t>::iterator end, Predicate pred, std::set<result_t> result)
    {
              // utils line 25
        typename std::set<result_t>::iterator nextResultElem = find_if(begin, end, pred);
        if (nextResultElem == end)
        {
            return result;
        }
        result.insert(*nextResultElem);

        return findAll_if_rec(++nextResultElem, end, pred, result);
    }
}

This produces the following compiler errors:

    algorithm(83): error C2064: term does not evaluate to a function taking 1 arguments
    algorithm(95) : see reference to function template instantiation '_InIt std::_Find_if<std::_Tree_unchecked_const_iterator<_Mytree>,_Pr>(_InIt,_InIt,_Pr)' being compiled
    1>          with
    1>          [
    1>              _InIt=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tset_traits<char,std::less<char>,std::allocator<char>,false>>>,
    1>              _Mytree=std::_Tree_val<std::_Tset_traits<char,std::less<char>,std::allocator<char>,false>>,
    1>              _Pr=bool (__thiscall Hangman::* )(char)
    1>          ]

utils.h(25) : see reference to function template instantiation '_InIt std::find_if<std::_Tree_const_iterator<_Mytree>,Predicate>(_InIt,_InIt,_Pr)' being compiled
    1>          with
    1>          [
    1>              _InIt=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<char,std::less<char>,std::allocator<char>,false>>>,
    1>              _Mytree=std::_Tree_val<std::_Tset_traits<char,std::less<char>,std::allocator<char>,false>>,
    1>              Predicate=bool (__thiscall Hangman::* )(char),
    1>              _Pr=bool (__thiscall Hangman::* )(char)
    1>          ]

utils.h(16) : see reference to function template instantiation 'std::set<_Kty> detail::findAll_if_rec<result_t,Predicate>(std::_Tree_const_iterator<_Mytree>,std::_Tree_const_iterator<_Mytree>,Predicate,std::set<_Kty>)' being compiled
    1>          with
    1>          [
    1>              _Kty=char,
    1>              result_t=char,
    1>              Predicate=bool (__thiscall Hangman::* )(char),
    1>              _Mytree=std::_Tree_val<std::_Tset_traits<char,std::less<char>,std::allocator<char>,false>>
    1>          ]

hangman.cpp(103) : see reference to function template instantiation 'std::set<_Kty> Utils::findAll_if<char,bool(__thiscall Hangman::* )(char)>(std::_Tree_const_iterator<_Mytree>,std::_Tree_const_iterator<_Mytree>,Predicate)' being compiled
    1>          with
    1>          [
    1>              _Kty=char,
    1>              _Mytree=std::_Tree_val<std::_Tset_traits<char,std::less<char>,std::allocator<char>,false>>,
    1>              Predicate=bool (__thiscall Hangman::* )(char)
    1>          ]
A: 

You need to use mem_fun

#include <functional>  
// ...  
set<char> Hangman::incorrectGuesses()
{  
   return Utils::findAll_if<char>(guesses.begin(), guesses.end(), 
                                  std::mem_fun(&Hangman::isIncorrectGuess));
}
a1ex07
I did that, and it didn't make a difference. The same error is still there.
Rosarch
I don't think You are correct. guesses seems to be set<char>. There are no pointers to Hangman to pass to the function objects created with mem_fun
Maciej Hehl
+1  A: 

You want Your predicate to be (or behave like) a simple function that takes a char and returns bool. The compiler complains that &Hangman::isIncorrectGuess is of type bool (__thiscall Hangman::* )(char) that is - it's a pointer to member to a non-static member function. Member function can't be simply called with char parameter, like a normal function, because it requires an object of Hangman to work on.

If it was possible to use a static function You could make isIncorrectGuess static but I guess the correctAnswer is a member of Hangman and the predicate needs an access to it. In that case use a binder like in Georg's answer.

Maciej Hehl
+3  A: 

Use the following to use a bound member function as a predicate:

return Utils::findAll_if<char>(
                   guesses.begin(), guesses.end(), 
                   std::bind1st(std::mem_fun(&Hangman::isIncorrectGuess), this)));

Member functions expect an implicit this parameter and can't be used directly with STL algorithms. Thus the above generates an adapter for the member function by using std::mem_fun and binds it to the current instance using std::bind1st.

You might want to look into Boost.Bind, which makes these things easier:

    return Utils::findAll_if<char>(
                   guesses.begin(), guesses.end(), 
                   boost::bind(&Hangman::isIncorrectGuess, this, _1));

The problem comes from the fact that the STL algorithms call the predicates etc. similar to this:

predicate(someParameter);

... which doesn't work for member functions. Member function pointers would have to be invoked using a special syntax and an instance or a pointer to one - e.g.:

(pointerToInstance->*predicate)(someParameter);

See e.g. this article for more on member pointers. Using std::mem_fun/std::bind1st or boost::bind you can generate adapters that do this and implement operator() which allows them to be called similar to common functions.

Georg Fritzsche
Can you explain exactly what's going on here?
Rosarch