2010-04-23 6 views
3

Source du problème -Accelerated C++, problème 8-5Problème passer une fonction de modèle comme un argument à une autre fonction en C++

J'ai écrit un petit programme qui examine les lignes d'entrée de chaîne, et compte le nombre de fois un mot apparaît sur une ligne donnée. Le code suivant accomplit ceci:

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

Comme vous pouvez le voir, la fonction divisée est une fonction de modèle pour gérer différents types d'itérateurs de sortie comme souhaité.

Mon problème vient quand je tente de généraliser la xref fonction en passant dans le fendu fonction basé sur un modèle comme argument. Je n'arrive pas à avoir le type correct. Donc, ma question est, pouvez-vous passer une fonction de modèle à une autre fonction comme un argument, et si oui, devez-vous déclarer tous les types avant de le passer? Ou le compilateur peut-il déduire les types de la façon dont la fonction modèle est utilisée dans le corps?

Pour démontrer les erreurs que je reçois, commentez la tête de la fonction Xréf existant et décommenter l'en-tête autre que je suis en train de faire travailler (juste en dessous de la ligne obtenir des commentaires ci-dessous.) Commentaire également les lignes marquées LINE 2 et ligne 3 et uncomment LINE 4, qui tente d'utiliser l'argument find_words (qui par défaut est divisé .)

Merci pour toute rétroaction!

+2

** S'il vous plaît essayer de poster des exemples de codes ** minimum. –

+0

En outre, il n'existe pas de "fonction de modèle" en C++. C'est un "modèle de fonction". –

+0

Et je pense qu'un simple 'using namespace std;' suffirait :-) –

Répondre

1

Ce qui suit est une solution de contournement. Vous pouvez utiliser une classe avec une fonction statique

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 
    } 

}; 

Maintenant, faire

générique 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)); 

}; 
+0

Merci pour la réponse. Je reçois toujours une erreur "Impossible de déduire l'argument du modèle pour 'FIND_WORDS'" lorsque j'effectue ces modifications. Je vais continuer à brancher et voir si je peux le faire fonctionner. – Darel

+0

ajouter tympename si nécessaire ou simplement remplacer find_words :: apply par find_words.apply –

+0

J'ai été en mesure de le faire fonctionner, mais pas avec le paramètre d'argument par défaut. J'ai dû créer un split "s", puis appeler xref (cin, s). Ce qui permet à xref d'appeler la fonction statique s.apply(). Ceci utilise xref (istream & in, FIND_WORDS s). J'ai essayé d'utiliser xref (cin) avec xref (istream & in, FIND_WORDS s = split) mais il ne compilerait pas - indique qu'aucune instance de xref ne correspond à la liste d'arguments. – Darel

1

Ou le compilateur peut-il déduire les types de la façon dont la fonction modèle est utilisée dans le corps?

La réponse à cette question est: Non

Vous aurez besoin de changer « typedef Out » du type qui back_inserter les retours et vous devrez fournir ce même type « = split <type_here> ".

Le type renvoyé par back_inserter est spécifié par le standard. Vous devriez donc pouvoir le trouver dans votre référence de bibliothèque C++.

Vous pouvez également essayer de transformer votre fonction xréf en un modèle prenant en paramètre un modèle de fonction (et son type). Je n'ai jamais rien essayé de tel, pas avec des fonctions de toute façon, donc je ne sais pas quel succès ça va apporter. Ce pourrait être ce que vous voulez, peut-être pas.

Si vous utilisiez C++ 0x, vous auriez quelques autres options qui pourraient fonctionner plus comme vous le souhaitez.

+0

Merci, je vais voir ce que je peux faire pour déterrer le type .. J'ai essayé, mais il est arrivé au point où je ne savais même pas que je pouvais passer un modèle de fonction comme argument, et une recherche google didn pas grand-chose. – Darel

Questions connexes