Проблема передачи шаблонной функции в качестве аргумента другой функции в C ++ - PullRequest
3 голосов
/ 23 апреля 2010

Источник проблемы - Ускоренный C ++, проблема 8-5

Я написал небольшую программу, которая проверяет строки ввода строки и подсчитывает, сколько раз слово появляется в данной строке. Следующий код выполняет это:

#include <map>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <cctype>
#include <iterator>

using std::vector;         using std::string;
using std::cin;            using std::cout;
using std::endl;           using std::getline;
using std::istream;        using std::string;
using std::list;           using std::map;
using std::isspace;        using std::ostream_iterator;
using std::allocator;

inline void keep_window_open()
{
    cin.clear();
    cout << "Please enter EOF to exit\n";
    char ch;
    cin >> ch;
    return;
}

template <class Out>
void split(const string& s, Out os)
{
    vector<string> ret;
    typedef string::size_type string_size;
    string_size i = 0;

    // invariant: we have processed characters `['original value of `i', `i)'
    while (i != s.size()) {
        // ignore leading blanks
        // invariant: characters in range `['original `i', current `i)' are all spaces
        while (i != s.size() && isspace(s[i]))
            ++i;

        // find end of next word
        string_size j = i;
        // invariant: none of the characters in range `['original `j', current `j)' is a space
        while (j != s.size() && !isspace(s[j]))
            ++j;

        // if we found some nonwhitespace characters
        if (i != j) {
            // copy from `s' starting at `i' and taking `j' `\-' `i' chars
            *os++ = (s.substr(i, j - i));
            i = j;
        }
    }
}


// find all the lines that refer to each word in the input
map<string, vector<int> > xref(istream& in)     // works
// now try to pass the template function as an argument to function - what do i put for templated type?
//map<string, vector<int> > xref(istream& in, void find_words(vector<string, typedef Out) = split)      #LINE 1#
{
    string line;
    int line_number = 0;
    map<string, vector<int> > ret;

    // read the next line
    while (getline(in, line)) {
        ++line_number;

        // break the input line into words
        vector<string> words;   // works            // #LINE 2#
        split(line, back_inserter(words));          // #LINE 3#
        //find_words(line, back_inserter(words));   // #LINE 4# attempting to use find_words as an argument to function

        // remember that each word occurs on the current line
        for (vector<string>::const_iterator it = words.begin();
             it != words.end(); ++it)
            ret[*it].push_back(line_number);
    }
    return ret;
}

int main()
{
    cout << endl << "Enter lines of text, followed by EOF (^Z):" << endl;

    // call `xref' using `split' by default
    map<string, vector<int> > ret = xref(cin);

    // write the results
    for (map<string, vector<int> >::const_iterator it = ret.begin();
         it != ret.end(); ++it) {
        // write the word
        cout << it->first << " occurs on line(s): ";

        // followed by one or more line numbers
        vector<int>::const_iterator line_it = it->second.begin();
        cout << *line_it;   // write the first line number

        ++line_it;
        // write the rest of the line numbers, if any
        while (line_it != it->second.end()) {
            cout << ", " << *line_it;
            ++line_it;
        }
        // write a new line to separate each word from the next
        cout << endl;
    }
    keep_window_open();
    return 0;
}

Как видите, функция split - это шаблонная функция для обработки различных типов выходных итераторов по желанию.

Моя проблема возникает, когда я пытаюсь обобщить функцию xref , передав в качестве аргумента шаблонную функцию split . Кажется, я не могу понять правильный тип.

Итак, мой вопрос: можете ли вы передать функцию шаблона другой функции в качестве аргумента, и если да, нужно ли объявлять все типы перед ее передачей? Или компилятор может определить типы по способу использования шаблонной функции в теле?

Чтобы продемонстрировать ошибки, которые я получаю, закомментируйте существующий заголовок функции xref и раскомментируйте альтернативный заголовок, который я пытаюсь получить (чуть ниже следующей строки комментария.) Также прокомментируйте помеченные строки LINE 2 и LINE 3 и раскомментируйте LINE 4, которая пытается использовать аргумент find_words (по умолчанию split .)

Спасибо за любые отзывы!

Ответы [ 2 ]

1 голос
/ 27 апреля 2010

Это обходной путь. Вы можете использовать класс со статической функцией

struct split
{
  template <class Out>
  static apply(const string& s, Out os) { 
    // include the body of your split function or call to an existing function
  }

};

Теперь сделайте xref generic

template <typename FIND_WORDS>
map<string, vector<int> > xref(istream& in, FIND_WORDS find_words = split()) 
{

  // replace #2 and #3 by
  find_words.apply(line, back_inserter(words));

}; 
1 голос
/ 23 апреля 2010

Или компилятор может определить типы по способу использования шаблонной функции в теле?

Ответ на этот вопрос: Нет.

Вам нужно изменить 'typedef Out' на тип, который возвращает back_inserter, и вам нужно будет указать этот же тип для "= split ".

Тип, который возвращает back_inserter, определяется стандартом, поэтому вы должны быть в состоянии найти его в своей ссылке на C ++ lib.

Вы также можете попробовать превратить вашу функцию xref в шаблон, который принимает шаблон функции в качестве параметра (и его тип). Хотя я никогда не пробовал ничего подобного, во всяком случае, не с функциями, поэтому я не знаю, какой успех это принесет. Это может быть тем, что вы хотите, а может и нет.

Если бы вы использовали c ++ 0x, у вас было бы еще несколько опций, которые могли бы работать больше, чем вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...