C ++: проблема с шаблонами (C2064) - PullRequest
1 голос
/ 28 мая 2010

У меня ошибки компилятора, и я не уверен, почему. Что я тут не так делаю:

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 ]

3 голосов
/ 28 мая 2010

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

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

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

1 голос
/ 28 мая 2010

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

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

0 голосов
/ 28 мая 2010

Вам нужно использовать mem_fun

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