开发者

C++: Trouble with templates (C2064)

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>    开发者_C百科          _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>          ]


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.


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.


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));
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜