2013-09-06 5 views
0

je rencontre quelques problèmes qui peuvent être repris par le morceau de code suivant:C++ fonctions comme arguments de modèle

template <typename Key, typename Data, typename fct> 
size_t wrapper(const std::pair<Key, Data> & p) 
{ 
    return fct(p.first); 
} 

int main(int argc, char *argv[]) 
{ 
    size_t val = 
    wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9)); 

    return 0; 
} 

J'utilise la version du compilateur clang 3.4 et ce code ne compilent pas avec l'erreur suivante

test-tmp.C:17:5: error: no matching function for call to 'wrapper' 
    wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9)); 
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
test-tmp.C:9:8: note: candidate template ignored: invalid explicitly-specified argument 
     for template parameter 'fct' 

l'idée est d'envelopper une fonction de hachage (le paramètre de modèle fct) sur std::pair pour ne prendre que le premier champ.

dft_hash_fct est un autre modèle définit comme suit:

template <typename Key> 
size_t dft_hash_fct(const Key & key) 
{ 
    return SuperFastHash(key); 
} 

Cette fonction générique fonctionne; il a été utilisé dans d'autres contextes.

Le but de tout ceci est de réutiliser un ensemble basé sur le hachage (pas de carte) comme une carte de clés pour des éléments de n'importe quel type. Le ser basé sur le hachage reçoit une fonction de hachage dans le temps de construction.

Merci pour vos commentaires (David, Andreï et Kazark)

Modifié:

Eh bien, je vois, typename fct est un type, donc je ne peux pas gérer en fonction de pointeur; désolé pour le trivia. Malheureusement, je crois que l'approche du passage de la fonction en tant que paramètre dans l'emballage ne fonctionne pas, parce que l'ensemble de hachage attend un pointeur de fonction avec la signature suivante:

size_t (*the_function)(const Key & key); 

Alors, réalisant cela, grâce à vos observations, J'ai changé le code en question à:

template <typename Key, typename Data, size_t (*fct)(const Key & k)> 
size_t wrapper(const std::pair<Key, Data> & p) 
{ 
    return (*fct)(p.first); 
} 

int main(int argc, char *argv[]) 
{ 
    size_t val = 
    wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9)); 

    return 0; 
} 

qui compile, relie et s'exécute. En outre, j'ai mis cette ligne:

size_t (*fct)(const std::pair<int, int>&) = 
    wrapper<int, int, dft_hash_fct<int>>; 

cout << (*fct)(std::pair<int, int>(4,6)) << endl; 

Et cela compile, relie et fonctionne aussi. Donc, je peux dire que le compilateur (et bien sûr selon le langage) peut instancier la fonction et gérer un pointeur de fonction. Donc, après cela, j'ai essayé de modifier mon code original, qui est une classe dérivée de HAshSet destinée à gérer des paires hachées par le premier champ.

Je déclare certains comme:

template <typename Key, typename Data> 
class HashMap : public HashSet<std::pair<Key, Data>> 
{ 
    ... 
    HashMap(size_t (*function)(const Key & key)) 
    : HashSet<Key, Data>(wrapper<Key, Data, function>) 
    { 

    } 

.. 
}; 

Mais la compilation (avec std = C++ 11) échoue avec l'erreur

./tpl_dynSetHash.H:353:7: error: no matching constructor for initialization of 
     'HashSet<std::pair<unsigned long, long>>' 
    : HashSet<std::pair<Key,Data>(
    ^
testDynSetHash.C:178:8: note: in instantiation of member function 
     'HashMap<unsigned long, long>::HashMap' requested here 
    HMap table; 

Cependant, si je remplace l'appel au constructeur de base par

: HashSet<Key, Data>(wrapper<Key, Data, dft_hash_fct<Key>) 

Cela compile bien. Ainsi, je crois que le problème est avec la déclaration de type de paramètre (mais je ne sais pas ce que c'est).

+2

Vous devez fournir un type pour un argument de modèle de type, mais vous avez fourni une fonction. – dyp

+0

Vous utilisez clang ++ 3.4, pouvez-vous/êtes-vous autorisé à utiliser les fonctionnalités C++ 11? – dyp

+0

1) Il vous manque un '' 'à la fin de' wrapper 'dans votre dernier bloc de code. 2) 'HashMap (size_t (* fonction) (const Clé et clé)): HashSet (wrapper )' n'est pas possible car 'function' n'est pas une constante de compilation ici (mais une fonction paramètre); Seules les constantes de compilation (expressions constantes) sont autorisées en tant qu'arguments de modèle non-type (je fais référence au troisième argument de 'wrapper <..>'). – dyp

Répondre

4

L'idiome standard pour passer des fonctions est de les passer en tant qu'objets de fonction, par ex.

template <typename Key, typename Data, typename Fct> 
size_t wrapper(const std::pair<Key, Data> & p, Fct fct) 
{ 
    return fct(p.first); 
} 

Ensuite, appelez l'emballage en utilisant:

int main(int argc, char *argv[]) 
{ 
    // no explicit template arguments required 
    size_t val = 
    wrapper(std::pair<int,int>(5,9), &dft_hash_fct<int>); 

    return 0; 
} 

Dans votre code, d'autre part:

template <typename Key, typename Data, typename fct> 
size_t wrapper(const std::pair<Key, Data> & p) 
{ 
    return fct(p.first); 
} 

typename fct introduit un alias pour un type. Dans cette fonction, fct attribue un nom à un type; par conséquent fct(p.first) crée un objet de type fct et cet objet doit être converti en size_t afin de le renvoyer de wrapper. Vous pouvez utiliser cela aussi, mais le type que vous deviez utiliser faudrait ressembler à ceci:

struct dft_hash_fct_t 
{ 
    size_t result; 
    dft_hash_fct_t(int p) : result(SuperFashHash(p)) {} 
    operator size_t() const { return result; } 
}; 

Ce qui est sans doute pas ce que vous vouliez.

+0

J'ai corrigé mon code avec votre obs et ceux de @AndreyT – lrleon

1

La déclaration de modèle dans

template <typename Key, typename Data, typename fct> 
size_t wrapper(const std::pair<Key, Data> & p) 
{ 
    return fct(p.first); 
} 

paramètre template déclare fct comme un type, mais vous essayez de passer un pointeur de fonction à lui. Vous pouvez faire le paramètre de modèle de pointeur de fonction fct comme ceci:

template <typename Key, typename Data, size_t(*fct)(const Key&)> 
size_t wrapper(const std::pair<Key, Data> & p) 
{ 
    return fct(p.first); 
} 

Cependant, le moyen le plus idiomatiques est (comme DPJ dit) de passer un objet de fonction pour que la fonction fonctionne avec des pointeurs de fonction ainsi que des objets de surcharge operator():

template <typename Key, typename Data, typename Fct> 
size_t wrapper(const std::pair<Key, Data> & p, Fct fct) 
{ 
    return fct(p.first); 
} 

Puis lors de l'appel que vous passez la fonction en tant que paramètre

wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>); 
1

le code que vous avez écrit make Il n'y a aucun sens dans le contexte de votre intention. Votre paramètre de modèle fct est un type. Cela signifie que

return fct(p.first); 

est un casting, pas une application de type fonction de () opérateur (à-dire qu'il n'est pas un appel de fonction). Dans votre code, vous tentez de lancer p.first pour taper fct, puis d'essayer de renvoyer le résultat de cette distribution sous la forme size_t. Était-ce votre intention? Je doute que c'était. En plus de cela, vous essayez de passer un pointeur de fonction valeurdft_hash_fct<int> comme argument de modèle pour fct, à savoir que vous passez une valeur où un type est prévu. Comment vous attendiez-vous à ce que cela fonctionne?

La description que vous avez fournie semble indiquer que vous vouliez réellement appeler un foncteur de type fct à l'intérieur de wrapper au lieu d'effectuer un cast. Pour ce faire, vous devez obtenir le foncteur lui-même. Rappelez-vous encore que fct n'est pas un foncteur, c'est juste le type du foncteur.

L'approche typique serait de passer le foncteur de l'extérieur, en tant que paramètre de la fonction

template <typename Key, typename Data, typename fct> 
size_t wrapper(const std::pair<Key, Data> & p, fct f) 
{ 
    return f(p.first); 
} 

vous pouvez maintenant utiliser votre modèle wrapper avec foncteurs de classe, ainsi que des fonctions ordinaires

size_t val = wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>); 

Notez que dft_hash_fct<int> doit être fourni en tant qu'argument de fonction et non en tant qu'argument de modèle. Il n'est pas nécessaire de spécifier explicitement les arguments du modèle, car ils seront déduits par le compilateur.

Questions connexes