2010-05-28 3 views
1

У меня возникают ошибки компилятора, и я не уверен, почему. Что я делаю неправильно здесь:C++: проблемы с шаблонами (C2064)

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

Это дает следующие ошибки компилятора:

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>   ] 

ответ

3

Используйте следующее использовать связанную функцию-член в качестве предиката:

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

функции-члены ожидают неявное this параметр и не может быть использован непосредственно с алгоритмами STL. Таким образом, приведенное выше генерирует адаптер для функции-члена с помощью std::mem_fun и связывает его с текущим экземпляром с использованием std::bind1st.

Вы можете посмотреть в Boost.Bind, что делает эти вещи проще:

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

Проблема возникает из-за того, что алгоритмы STL называют предикаты и т.д., подобные этим:

predicate(someParameter); 

... который не работает для функций-членов. Функция член указатели должны быть вызваны с помощью специального синтаксиса и экземпляр или указатель на один - например .:

(pointerToInstance->*predicate)(someParameter); 

См, например this article Подробнее о указателях участников. Используя std::mem_fun/std::bind1st или boost::bind, вы можете сгенерировать адаптеры, которые делают это и реализуют operator(), что позволяет их называть похожими на общие функции.

+0

Можете ли вы точно объяснить, что здесь происходит? –

0

Вам нужно использовать меня m_fun

#include <functional> 
// ... 
set<char> Hangman::incorrectGuesses() 
{ 
    return Utils::findAll_if<char>(guesses.begin(), guesses.end(), 
            std::mem_fun(&Hangman::isIncorrectGuess)); 
} 
+0

Я сделал это, и это не имело значения. Такая же ошибка все еще существует. –

+0

Я не думаю, что ты прав. догадки, похоже, установлены . Нет указателей на Hangman, чтобы перейти к объектам функции, созданным с помощью mem_fun. –

1

Вы хотите, чтобы ваш предикат быть (или вести себя как) простая функция, которая принимает и возвращает charbool. Компилятор жалуется, что &Hangman::isIncorrectGuess имеет тип bool (__thiscall Hangman::*)(char), то есть - это указатель на член для нестатической функции-члена. Функция-член не может быть просто вызвана с параметром char, как обычная функция, потому что для этого требуется объект Hangman.

Если бы можно было использовать статическую функцию, вы могли бы сделать isIncorrectGuess статическим, но я думаю, что correctAnswer является членом Hangman, и предикат нуждается в доступе к нему. В этом случае используйте связующее, как в ответе Георга.

Смежные вопросы