2012-04-13 4 views
4

Zur Zeit bin ich mit etwas Code wie fooA() fest (achten Sie nicht auf den Körper), die einen bestimmten Container erwartet, sagen vector<double>, als Argument.Pass Iterator anstelle von Container

double fooA(std::vector<double> const& list) 
{ 
    return list[0]; 
} 

Jetzt will ich Iteratoren verallgemeinern und stattdessen zu verwenden:

template<typename InputIterator> 
double fooB(InputIterator first, InputIterator last) 
{ 
    return *first; 
} 

Wie erklären, dass fooB() den Iterator über double iterieren erfordert?

Jemand könnte eine vector<string>::iterator oder, noch schlimmer, wie es ohne eine Warnung kompilieren könnte, eine vector<int>::iterator übergeben.

+0

Vielleicht meinen Sie, dass Sie angeben müssen, dass der Iterator über Doppel durchlaufen muss? –

+0

Heh, das kann gemacht werden, aber es ist nicht schön. Ich empfehle, nur einen Kommentar zu schreiben, da der Rückgabetyp erzwingt, dass der Iteratortyp zumindest in ein "double" konvertiert wird. –

+0

'double' statt' int' natürlich. Das habe ich korrigiert, danke. Mein "realer Weltrückgabetyp" hängt nicht vom Iterator ab ... –

Antwort

4

Für C++ 03:

#include <iterator> 
#include <boost/type_traits/is_same.hpp> 
#include <boost/type_traits/remove_cv.hpp> 
#include <boost/utility/enable_if.hpp> 

template<typename InputIterator> 
typename boost::enable_if< 
    boost::is_same< 
     typename boost::remove_cv< 
      typename std::iterator_traits<InputIterator>::value_type 
     >::type, 
     double // expected value_type 
    >, 
    double  // fooB return type 
>::type 
fooB(InputIterator first, InputIterator last) 
{ 
    return *first; 
} 

Eine andere C++ 03-Lösung, die nicht-Boost verwendet, sondern wird wahrscheinlich produziert viel hässliche Fehler, wenn eine ungültige Art vorbei:

#include <iterator> 

void fooB_helper(double) { } 
template<typename T> void fooB_helper(T const&); 

template<typename InputIterator> 
double fooB(InputIterator first, InputIterator last) 
{ 
    fooB_helper(typename std::iterator_traits<InputIterator>::value_type()); 
    return *first; 
} 

Für C++ 11 können Sie den Ausdruck SFINAE anstelle von enable_if verwenden, oder Sie können static_assert anstelle von SFINAE insgesamt verwenden.

0

Wenn Sie Boost-nicht verwenden möchten/C++ 11, könnten Sie in der Lage sein, mit diesem Ansatz wegzukommen:

template<typename B, template<typename A1, typename B1> class Container> 
double fooB(typename Container<int, B>::iterator first, 
    typename Container<int, B>::iterator last) 
{ 
    return 0; 
} 

rufen:

vector<int> a; 
fooB<vector<int>::allocator_type, vector>(a.begin(), a.end()); 

Ein bisschen hässlich , aber funktioniert :)

Auch: nicht portierbar wie die std collection Implementierungen können mehr als zwei Template-Parameter haben (der zweite ist ein Allokator mit einem Standardwert)

+0

Die stdlib-Sammlungen haben mindestens zwei Vorlagenargumente, aber sie dürfen mehr haben, solange die zusätzlichen Standardwerte haben. Das heißt, dieser Code ist nicht tragbar. – ildjarn

Verwandte Themen