6
votes

Pourquoi dois-je spécifier le type d'argument de modèle d'une fonction modélisée ici?

J'ai le code suivant: xxx

dans la fonction foo () J'ai besoin de spécifier l'argument de modèle, même si f1 (t) est une expression valide. C'est un peu détruisant certaines possibilités de mon code. Mes questions:

  1. Pourquoi dois-je spécifier l'argument de modèle?
  2. Comment puis-je travailler autour de cette limitation? (C ++ 11 ou C ++ 14 admis).

    (BTW: J'utilise actuellement Visual Studio 2010 et je reçois l'erreur C2896, si je quitte le out.)


0 commentaires

6 Réponses :


11
votes

F1 n'est pas une fonction, c'est un modèle. Vous ne pouvez pas transmettre un modèle en tant qu'argument de la fonction.

F1 est une fonction, de sorte qu'il peut être transmis.


0 commentaires

1
votes

F1 (t) n'est pas une expression valide, car il n'y a pas de fonction F1 . Il n'y a que un modèle nommé F1 à partir de laquelle une fonction f1 peut être généré sur l'heure de la compilation.

Cette la limitation Vous parlez est une conséquence directe de la vérification du type de temps de compilation. Si vous connaissez le type d'argument de FOO au moment de la compilation, il n'y a pas de limitation, puisque vous l'ajoutez facilement. Si vous ne connaissez pas le type de l'argument, vous devrez peut-être utiliser un modèle de classe dérivé au lieu d'une idée template.


4 commentaires

Bien sûr, F1 (t) est une expression valide à l'intérieur foo () . Il compile bien.


Le modèle de déduction par paramètre de modèle ne fonctionne pas dans des modèles spécifiques, peut-être que cette question répond à votre question: Stackoverflow.com/Questtions/1268504/...


@AlphTeTzky: Peu importe ce que pourrait une expression valide tel qu'il est utilisé à l'intérieur de FOO . Les modèles sont pas de macros ; Ils ne prennent rien et collez les jetons ensemble après. Votre fonction de modèle prend un f && f . C'est un paramètre de fonction; Ce doit être une valeur , qui a un type . Les modèles ne sont pas des valeurs ni n'ont des types. Par conséquent, ils ne peuvent pas être transmis en tant que paramètres de fonction.


@AlphTeTezky: Oui, F1 (t) est une expression valide en raison de la déduction de l'argument de modèle de fonction. Le compilateur peut en déduire, basé sur le type du paramètre t , quelle instanciation de la template de fonction F1 Pour appeler - il remplace le F1 (t) avec F1 (t) . Ceci est essentiellement juste un peu de sucre syntaxique. Lorsque vous souhaitez transmettre une instanciation du modèle F1 autour du modèle, le compilateur ne peut pas vous aider et vous devez spécifier lequel vous voulez.




3
votes

Vous pouvez essayer d'envelopper les fonctions modèles F1 et F2 dans des classes non modèles et des instances de passage (ou même des types) autour, par exemple xxx

qui produit la sortie:

f1 :: opérateur () (1) appelé

f2 :: opérateur () (1) appelé


1 commentaires

+1 C'est une belle variation de la même idée que j'ai utilisée dans ma réponse. Toutefois, cela pourrait être utile (cela dépend des exigences de l'OP) pour effectuer appel , au lieu de recevoir un f , créez une instanciation locale construite par défaut de celle-ci. Ensuite, dans foo , nous pourrions utiliser appel (t); .



8
votes

1. Pourquoi dois-je spécifier l'argument de modèle?

Eh bien, F1 n'est pas un objet, mais un modèle de fonction. Vous ne pouvez transmettre que des objets à des fonctions.

2. Comment puis-je travailler autour de cette limitation? (C ++ 11 ou C ++ 14 admis).

Utilisez un objet avec un opérateur modèles () . Il suffit de remplacer la définition de F1 () avec xxx

et de même pour f2 () . En C ++ 14, vous pouvez l'écrire même plus agréable xxx


1 commentaires

Grâce à tous les autres intervenants pour leurs intrants inspirants.



1
votes

Il existe un moyen d'imiter les modèles de fonctions de passage (ou des ensembles de surcharge) en tant que valeurs de première classe: "les réinservent" en les transformant en objets de la fonction. Votre code pourrait être réécrit comme celui-ci:

struct F1
{
  template <typename T>
  void operator ()( T t )
  {
    std::cout << "f1( " << t << " ) called." << endl;
  }
} f1;

struct F2
{
  template <typename T>
  void operator ()( T t )
  {
    std::cout << "f2( " << t << " ) called." << endl;
  }
} f2;

// Note that this function didn't change at all!
template <typename F, typename T>
void call( F && f, T t )
{
    f( t );
}
// Neither did this, expect that now you don't need the <T>
template <typename T>
void foo( T t )
{
    call( f1, t );
    call( f2, t );
}

void bar()
{
    foo( 1 );
    foo( 3.14 );
    foo( "Hello World" );
}


0 commentaires