2010-01-17 2 views
5

Was ich meine, ist das Folgende. Ich möchte eine Template-Funktion, die zwei Vektor-Iteratoren (oder zwei Zeiger auf ein Doppel-Array) benötigt und ein Double zurückgibt, das irgendwie mit den Vektor-Iteratoren oder Array-Zeigern in Beziehung steht, die ich überlasse. Ich möchte jedoch, dass dies für double oder int oder einen beliebigen arithmetischen Typ funktioniert.Kann ich in einer C++ - Template-Funktion einen dereferenzierten Argumenttyp zurückgeben?

Ich glaube, ich bin nicht erlaubt zu sagen:

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

T new_variable = Begin + 5; 

return (*new_variable); 
} 

, da der Compiler nicht verstehen, was T * Mittel. Eine Lösung, die ich gedacht ist zu nehmen, was ich versuche, es ein drittes Argument zurück und machen:

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

new_variable = Begin + 5; 

return (*new_variable); 
} 

Wird diese Arbeit? Selbst wenn ja, gibt es eine andere Art zu tun, was ich versuche zu tun? (Sorry, wenn ich nicht klar genug.)

+3

Beachten Sie, dass der Compiler 'T *' im Rückgabetyp einer Vorlagenfunktion versteht; Das Problem ist, dass der Typ von '* new_variable' nicht' T * 'ist. – outis

Antwort

10

Wenn Sie ein Doppel zurückkehren möchten (dh die Art, die Sie erhalten würden, wenn dereferencing), können Sie die Iterator Merkmale verwenden:

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

Diese Arbeit für alle Iteratoren, einschließlich Zeiger:

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

Das scheint genau das zu sein, was ich brauchte! Ein paar Punkte allerdings: 1) Ich glaube, Sie haben vergessen, die for-Schleife zu initialisieren. 2) Ist es OK, wenn Sie typedef verwenden, um einen neuen Typ zu nennen, um es value_type zu nennen? Ist das nicht ein reserviertes Keyword oder etwas? 3) Ich wusste nichts über iterator_traits, weil ich Accelerated C++ lese. Kann ich in Josuttis Buch mehr darüber erfahren? – jackj

+2

@jackj 1) Sie können den for-loop Anfangsabschnitt weglassen, wenn Sie ihn nicht brauchen. "t" wird vollständig auf den Standardwert value_type initialisiert (0 für int), 2) Ja, value_type ist nicht reserviert. Wir können damit den langen Typnamen verkürzen. 3) ja josuttis Buch sollte dies abdecken. :) –

+0

Wow! Dies ist mein erstes Mal auf Stackoverflow, aber ich weiß, dass ich zurückkommen werde. Ihr seid fantastisch! Vielen Dank. – jackj

3

Nun, Ihr Code scheint zu widersprechen, was Sie im Text beschrieben. Wenn T der Iteratortyp ist, dann wird das Ergebnis des Iterators dereference (wie Sie im Text sagten) nicht haben Typ T * (wie Sie scheinen, an den Code zu glauben). T * ist eine völlig entgegengesetzte Sache: Es ist etwas, was Sie erhalten würden, wenn Sie die Adresse Ihres Iterators genommen, nicht dereferenziert.

In der Tat gibt es keine Möglichkeit, den "dereferenzierten Typ" mit C++ Kernsprachfunktionen auszudrücken (vielleicht decltype wird es in Zukunft tun, wie in decltype(*T())). Die einzige Möglichkeit, das Ergebnis der Dereferenzierung des Typs T zu beschreiben, ist die Verwendung einer Bibliotheks-basierten Lösung: Iterator-Traits, wie Johannes in seiner Antwort erklärte.

+0

Danke Outis und AndreyT. Du hast Recht, der Code widerspricht dem, was ich dachte. Ich glaube, ich wurde durch die Tatsache verwirrt, dass in C++ das unäre * verwendet wird, um einen Zeiger zu deklarieren und auch einen Zeiger oder einen Iterator zu dereferenzieren, aber diese beiden Dinge sind getrennt. – jackj

+1

@jackj: Das liegt daran, dass Sie die Deklaration 'T * id' lesen sollen, da" der Typ von '* id'' 'T' ist: was leider zu Fehlern wie' T * a, b; 'führt a 'T *' und ein 'T'.Das ist auch der Grund, warum es 'T id [n]' nicht 'T [n] id 'ist: weil der Typ von' id [n]' 'T' ist. –

+1

@jackj: Wenn Sie Probleme mit Typdeklarationen haben, lesen Sie http://unixwiz.net/techtips/reading-cdecl.html oder http://www.ericgiguere.com/articles/reading-c-declarations. html. Die einfachste Beschreibung, die ich gesehen habe (und der Grund für die Syntax) kommt von http://cm.bell-labs.com/cm/cs/who/dmr/chist.html: Stellen Sie sich vor, die Deklaration ist ein Ausdruck, dessen Wert ist der Typ, der am Anfang der Deklaration genannt wird (zB für 'T (* d) [2]', denke an '(* d) [1]' als ein 'T'). – outis