2011-01-06 17 views
2

Gibt es eine übliche Methode, um den benutzerdefinierten 'assign' Funktor loszuwerden? std :: transformieren könnte groß sein, aber nach C++ Standard verbietet Änderung der QuellenelementeJedes Element der Sammlung ändern

Ziel Sammlung Elementen als mehr deklarativen Ansatz wie möglich

template <typename T> 
struct assign : std::binary_function<T, T, void> { 
    void operator()(const T& source, T& dest) { 
     dest = source; 
    } 
}; 

int main() { 
    static boost::array<int, 5> arr = { 1, 2, 3, 4, 5 }; 
    std::for_each(arr.begin(), arr.end(), 
     boost::bind(assign<int>(), boost::bind(std::plus<int>(), _1, 3), _1)); 
    return 0; 
} 
+0

Gute Frage. Das Ändern jedes Elements würde die Konvertierung von Textzeichenfolgen in Klein- oder Großbuchstaben ermöglichen. –

Antwort

3

std zu ändern ist :: transform() erlaubt es dem Ausgabe-Iterator, auf das gleiche Element wie den Anfang des Eingabebereichs zu zeigen. Siehe here. Das Codebeispiel zeigt dies im Wesentlichen in der Zeile, die eine Transformation mit zwei Eingabebereichen zeigt. Der Ausgabe-Iterator ist derselbe wie der erste Eingabe-Iterator. Macht es das schmackhafter?

+1

Ja, das funktioniert. Aber der Standard sagt (siehe 25.3.4 Transform): ... op und binary_op sollen Iteratoren oder Teilbereiche nicht ungültig machen oder Elemente in den Bereichen [first1, last1] ändern ... – Voivoid

+0

Das ändert die Elemente nicht, sie werden ersetzt Sie. Dies macht die Iteratoren nicht ungültig. – OrangeDog

+0

Es ändert, worauf der Iterator zeigt, nicht der Iterator selbst. Auf den neuen Wert wird immer noch von demselben Iterator verwiesen. –

2

Versuchen Boost.Lambda:

int main() { 
    using namespace boost::lambda; 
    static boost::array<int, 5> arr = { 1, 2, 3, 4, 5 }; 
    std::for_each(arr.begin(), arr.end(), _1 += 3); 
    return 0; 
} 

Doch was nur ein "for_each" Schleife:

int main() { 
    static boost::array<int, 5> arr = { 1, 2, 3, 4, 5 }; 
    BOOST_FOREACH(int& n, arr) { 
     n += 3; 
    } 
    return 0; 
} 
+0

Danke.boost :: lambda sieht gut aus. BOOST_FOREACH ist auch großartig, aber es erlaubt nicht, die benötigte Sequenz mit dem Iteratorpaar zu spezifizieren. Dennoch frage ich mich, ob std :: transform verwendet werden könnte, um die Eingabefolge zu ändern. Irgendwelche Kommentare würden geschätzt – Voivoid

1

Was @gregg sagte Plus:

Die Formulierung in der Norm (N1905 25.2.3 Absatz 2) verbietet der Transformationsfunktion, Elemente in den gegebenen Bereichen direkt zu modifizieren, dh sie kann nicht in einen Eingabe-Iterator schreiben. Es soll nur einen Wert berechnen, den die transform-Funktion dann dem result Iterator zuordnet. In der Tat erlaubt Absatz 5 ausdrücklich result gleich first zu sein.

Ich denke, dies kann Implementierungen erlauben, Sicherheitsprüfungen oder Optimierungen in bestimmten Fällen durchzuführen.

Nehmen wir zum Beispiel an, transform sei auf std::vector<char> spezialisiert. Auf einer 32-Bit-Maschine könnte die Implementierung die Hauptschleife viermal abwickeln und 32-Bit-Lasten und -Speicher anstelle von 8-Bit-Einsen ausführen. Dies würde natürlich nicht funktionieren, wenn der erste Aufruf der Transformationsfunktion den Eingabebereich modifiziert hätte (die verbleibenden 3 Aufrufe vor dem Speicher würden dann mit schmutzigen Daten arbeiten).

Hier sind C++ 03 Einzeiler 3 aus arr jeden Wert hinzuzufügen:

std::transform(arr.begin(), arr.end(), arr.begin(), std::bind1st(std::plus<int>(), 3));

Verwandte Themen