2010-01-17 5 views
5

Ce que je veux dire est le suivant. Je veux une fonction template qui prend deux itérateurs vectoriels (ou deux pointeurs sur array of double) et renvoie un double qui est en quelque sorte lié aux itérateurs vectoriels ou aux pointeurs de tableau que je passe. Cependant, je veux que cela fonctionne pour double ou int, ou n'importe quel type arithmétique.Dans une fonction de modèle C++, puis-je retourner un type d'argument déréférencé?

Je pense que je ne suis pas autorisé à dire:

template <class T> 
T* func(T Begin, T End) 

T new_variable = Begin + 5; 

return (*new_variable); 
} 

parce que le compilateur ne comprendront pas ce T * signifie. Une solution que je pensais est de prendre ce que je suis en train de revenir et en faire un troisième argument:

template <class T> 
void func(T Begin, T End, T* new_variable) 

new_variable = Begin + 5; 

return (*new_variable); 
} 

Est-ce que ce travail? Même si c'est le cas, y a-t-il une autre façon de faire ce que j'essaie de faire? (Désolé si je ne l'ai pas été assez clair.)

+3

Notez que le compilateur comprend 'T *' dans le type de retour d'une fonction de modèle; le problème est que le type de 'new_variable' n'est pas' T * '. – outis

Répondre

10

Si vous voulez retourner un double (à savoir le type que vous obtenez lorsque déréférencement), vous pouvez utiliser les traits de iterator:

template<typename RandomAccessIterator> 
typename std::iterator_traits<RandomAccessIterator>::value_type 
func(RandomAccessIterator a, RandomAccessIterator b) { 
    typedef typename std::iterator_traits<RandomAccessIterator>::value_type 
     value_type; 

    // use value_type now, when you want to save some temporary 
    // value into a local variable, for instance 
    value_type t = value_type(); 
    for(; a != b; ++a) t += *a; 
    return t; 
} 

Ces travailler pour tous les itérateurs, y compris les pointeurs:

int main() { 
    int d[3] = { 1, 2, 3 }; 
    assert(func(d, d + 3) == 6); 
} 
+0

Cela semble être exactement ce dont j'avais besoin! Quelques points cependant: 1) Je pense que vous avez oublié d'initialiser la boucle for. 2) Est-ce OK quand vous utilisez typedef pour nommer un nouveau type pour l'appeler value_type? N'est-ce pas un mot-clé réservé ou quelque chose? 3) Je ne connaissais pas iterator_traits parce que je lis Accelerated C++. Puis-je en savoir plus dans le livre de Josuttis? – jackj

+2

@jackj 1) Vous pouvez omettre la section initiale pour la boucle si vous n'en avez pas besoin. "t" est entièrement initialisé à la valeur par défaut de value_type (0 pour int), 2) Oui, value_type n'est pas réservé. Nous pouvons l'utiliser pour raccourcir le nom de type long. 3) Oui, le livre de josuttis devrait couvrir ceci. :) –

+0

Wow! C'est ma première fois sur stackoverflow, mais je sais que je reviendrai. Vous êtes géniaux les gars! Merci beaucoup. – jackj

3

Eh bien, votre code semble contredire ce que vous avez décrit dans le texte. Si T est le type d'itérateur, alors le résultat de l'itérateur déréférencer (comme vous l'avez dit dans le texte) pas avoir le type T * (comme vous semblez croire dans le code). T * est une chose complètement opposée: c'est quelque chose que vous obtiendriez si vous preniez l'adresse de votre itérateur, pas déréférencé.

En fait, il n'y a aucun moyen d'exprimer le "type déréférencé" en utilisant les fonctionnalités du langage C++ (peut-être que decltype le fera dans le futur, comme dans decltype(*T())). La seule façon de décrire le résultat du déréférencement de type T consiste à utiliser une solution basée sur une bibliothèque: les caractères itératifs, comme Johannes l'a expliqué dans sa réponse.

+0

Merci outis et AndreyT. Vous avez raison, le code contredit ce que je pensais qu'il se passait. Je devine que je suis confus par le fait qu'en C++ l'unaire * est utilisé pour déclarer un pointeur, et aussi pour déréférencer un pointeur ou un itérateur, mais ces deux choses sont séparées. – jackj

+1

@jackj: C'est parce que vous êtes supposé lire la déclaration 'T * id' car" le type de '* id' est' T' ": ce qui conduit malheureusement à des bugs comme' T * a, b; ', qui définit un 'T *' et un 'T'.C'est aussi pourquoi 'T id [n] 'n'est pas' T [n] id': parce que le type de' id [n] 'est' T'. –

+1

@jackj: Si vous rencontrez des problèmes avec les déclarations de type, essayez de lire http://unixwiz.net/techtips/reading-cdecl.html ou http://www.ericgiguere.com/articles/reading-c-declarations. html La description la plus simple que j'ai vue (et la raison de la syntaxe) vient de http://cm.bell-labs.com/cm/cs/who/dmr/chist.html: imaginez que la déclaration est une expression dont la valeur est le type nommé au début de la déclaration (par exemple pour 'T (* d) [2]', pensez à '(* d) [1]' comme étant un 'T'). – outis

Questions connexes