简体   繁体   English

麻烦将模板函数作为参数传递给C ++中的另一个函数

[英]Trouble passing a template function as an argument to another function in C++

Source of the problem -Accelerated C++, problem 8-5 问题的根源 - 加速C ++,问题8-5

I've written a small program that examines lines of string input, and tallies the number of times a word appears on a given line. 我写了一个小程序来检查字符串输入的行,并计算一个单词出现在给定行上的次数。 The following code accomplishes this: 以下代码完成此操作:

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

As you can see, the split function is a template function to handle various types of output iterators as desired. 如您所见, split函数是一个模板函数,可根据需要处理各种类型的输出迭代器。

My problem comes when I try to generalize the xref function by passing in the templated split function as an argument. 当我尝试通过将模板化的split函数作为参数传递来推广xref函数时,我的问题出现了。 I can't seem to get the type correct. 我似乎无法得到正确的类型。

So my question is, can you pass a template function to another function as an argument, and if so, do you have to declare all types before passing it? 所以我的问题是,您是否可以将模板函数作为参数传递给另一个函数,如果是这样,您是否必须在传递之前声明所有类型? Or can the compiler infer the types from the way the templated function is used in the body? 或者编译器可以从模板化函数在体内使用的方式推断出类型?

To demonstrate the errors I get, comment out the existing xref function header, and uncomment the alternate header I'm trying to get working (just below the following commment line.) Also comment the lines tagged LINE 2 and LINE 3 and uncomment LINE 4, which is attempting to use the argument find_words (which defaults to split .) 为了演示我得到的错误,请注释掉现有的外部参照函数标题,并取消注释我正在尝试使用的备用标题(正好在下面的通信行下面。)同时注释标记为LINE 2和LINE 3的行并取消注释LINE 4 ,它试图使用参数find_words (默认为拆分 。)

Thanks for any feedback! 感谢您的任何反馈!

Or can the compiler infer the types from the way the templated function is used in the body? 或者编译器可以从模板化函数在体内使用的方式推断出类型?

The answer to that question is: No. 这个问题的答案是:不。

You'll need to change 'typedef Out' to the type that back_inserter returns and you'll need to supply that same type to "= split<type_here>". 您需要将'typedef Out'更改为back_inserter返回的类型,并且您需要将相同的类型提供给“= split <type_here>”。

The type that back_inserter returns is specified by the standard so you should be able to find that in your C++ lib reference. back_inserter返回的类型由标准指定,因此您应该能够在C ++库引用中找到它。

You might also try turning your xref function into a template that takes a function template as parameter (and its type). 您也可以尝试将外部参照功能转换为一个模板,该模板将函数模板作为参数(及其类型)。 I've never tried anything like that though, not with functions anyway, so I don't know how much success it will bring. 我从来没有尝试过类似的东西,但不管功能如何,所以我不知道会带来多少成功。 It might be what you want, might not. 它可能是你想要的,也可能不是。

If you were using c++0x you'd have a few more options that might work more like you wish. 如果您使用的是c ++ 0x,那么您可以选择更多可能更符合您需求的选项。

The following is a workaround. 以下是一种解决方法。 You can use a class with a static function 您可以使用具有静态函数的类

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
  }

};

Now, make xref generic 现在,使xref成为通用的

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

}; 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM