2016-07-21 5 views
1

Ich habe versucht, eine Funktion zu machen, die alle Elemente eines std::vector fasst:C++ Art von dereferenzierte Iterator

template<typename IteratorT> 
auto sum(IteratorT first, IteratorT last) -> decltype(*first) { 
    decltype(*first) sum = 0; 
    for (; first != last; ++first) 
     sum += *first; 

    return sum; 
} 

und ich habe diesen Fehler:

cannot convert from 'int' to 'int&'

Dann, nach einigen Recherchen ich diese gefunden: std::iterator_traits<IteratorT>::difference_type. Geändert meinen Code:

template<typename IteratorT> 
auto sum(IteratorT first, IteratorT last) -> typename std::iterator_traits<IteratorT>::difference_type { 
    std::iterator_traits<IteratorT>::difference_type sum = 0; 
    for (; first != last; ++first) 
     sum += *first; 

    return sum; 
} 

und es hat funktioniert, aber ich bin nicht sicher, warum, und wenn es eine gute Lösung ist oder nicht. Abschließend habe ich zwei Fragen:

1) Warum decltype(*first) kehrt int& und nicht int wie erwartet ich
2) Was genau typename vor std::iterator_traits<IteratorT>::difference_type funktioniert und warum sum Funktion funktioniert nicht, wenn ich es entfernen

+1

Ich hoffe, Sie tun dies nur als Übung, denn wir haben bereits ['std :: accumulate'] (http://en.cppreference.com/w/cpp/algorithm/accumulate). –

+0

Ja, ich weiß. Ich versuche nur, mehr über Iteratoren zu lernen. – DimChtz

+0

In C++ 14, entfernen Sie einfach '-> declltype (* zuerst)'. In C++ 11 müssen Sie entweder 'declltype' besser verstehen oder einfach einen echten Return-Typ verwenden (nämlich' std :: iterator_traits :: value_type'). Ersetzen Sie auch 'declltype (* first) sum 'mit diesem Typ. –

Antwort

0

Es gibt zwei Hauptprobleme:

  • Die Art von aa dereferenzierte Iterator ist eine Referenz, kann es const sein und für eine std::vector kann es sehr sein unterscheidet sich vom Elementtyp des Vektors.

  • Wenn der Elementtyp z.B. bool, möchten Sie nicht die Summe in bool Art zu tun.

Der folgende Code ist eine Lösung:

#include <iterator>  // std::iterator_traits 

template< class Iter > 
auto sum(Iter first, Iter last) 
    -> decltype(typename std::iterator_traits<Iter>::value_type() + 0) 
{ 
    decltype(typename std::iterator_traits<Iter>::value_type() + 0) sum = 0; 
    for (; first != last; ++first) 
     sum += *first; 
    return sum; 
} 

#include <iostream> 
#include <vector> 
#include <utility> 
using namespace std; 

#define ITEMS(x) begin(x), end(x) 

auto main() 
    -> int 
{ 
    vector<double> const v1 = {3, 1, 4, 1, 5}; 
    cout << sum(ITEMS(v1)) << endl; 

    vector<bool> const v2 = {0, 1, 1, 0, 1}; 
    cout << sum(ITEMS(v2)) << endl; 
} 

Beachten Sie, dass Sie Ihren eigenen nicht definieren sum: Es gibt std::accumulate.

+0

Danke, und ja ich bin mir bewusst von 'std :: accumum'. Ich versuche nur zu lernen. – DimChtz

+0

Btw, was '+ 0' hier wirklich tut:' typename std :: iterator_traits :: value_type() + 0'? – DimChtz

+0

Es fördert den Typ bis mindestens "int". –

-1

Sie hat eine zufällige Sache gemacht, die zufällig funktioniert. distance_type hat nichts mit Ihrem Problem zu tun, es ist ein Typ, der das Ergebnis der Messung einer Entfernung zwischen zwei Iteratoren bezeichnet. Da es sich meistens um einen Integer-Typ handelt, konnten Sie ihn in Ihrer Arithmetik verwenden.

Die ursprüngliche Frage war auf die Tatsache zurückzuführen, dass dereferencing einen Iterator gibt einen (const) Zeiger auf das darunter liegende Objekt - und dies erforderlich ist, so dass Code wie

*it = 10; 

würde tun, was Sie tun wollen (oder konnte nicht für konstante Iteratoren kompiliert werden).

Und das typename Schlüsselwort ist erforderlich, aber es gibt genug Duplikate hier auf typename Verwendung hier bereits.

0

decltype(*first) gibt eine Referenz, wie sonst würden wir die Dinge nicht wie

schreiben Lage sein
*first = 7; 

difference_type In Bezug auf es ist nicht klar, was Sie zu tun versucht. Das Wort typename wird benötigt, um dem Compiler mitzuteilen, dass ein sogenannter abhängiger Typ (der übliche Fall ist ein beliebiger Typ nach einer ::) eine Vorlage und kein Wert ist.

0

Versuchen Sie folgendes:

#include <type_traits> 

template < 
    typename Iter, 
    typename Ret = typename std::decay<decltype(*std::declval<Iter>())>::type> 
Ret f(Iter first, Iter last) 
{ 
    Ret sum {}; 
    for (; first != last; ++first) { sum += *first; } 
    return sum; 
} 
+0

Okay, ich muss fragen, ist dies: 'std :: zerfallen ())> :: type' besser als das: 'std :: iterator_traits :: value_type' – DimChtz

+0

[Demo] (http://melpon.org/wandbox/permlink/XvGudoftFdXbjNsK) –

+0

@DimChtz: Was? bedeutet "besser"? Sie sind zwei verschiedene Dinge. Verwenden Sie die, die Ihr Design erfordert. –