Werbung

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen

clang? gleichzeitig über mehrere Container laufen

Dieses Thema im Forum "C/C++" wurde erstellt von -AB-, 22. August 2016.

  1. -AB-

    -AB- Well-Known Member c-b Team

    Moin moin allerseits :)

    Hier hat doch sicher jemand clang, und mag mal meinen Code testen? Ich hab gehört, bei variadic templates ist clang da etwas picky, jedenfalls verglichen mit dem GCC.

    Gerne lass ich auch mal einen Visual C++ drüber laufen ;)

    Kurz eine kleine Vorstellung, was der Code können soll...


    Man kennt es ja, jemand dachte sich, besonders schlau zu sein und hat statt eines std::vector<MyStruct> zwei co-indizierte Vektoren angelegt, also: Zwei Container gleicher Länge, deren Objekte mit gleichem Index in irgendeiner Beziehung verwandt sind.

    Manchmal bekommt man aus einer API auch bloß Daten auf diese Art heraus (Vertices und Oberflächennormale, IDs und Namen von Objekten, ...), so oder so haben wir jetzt aber folgendes Dilemma:

    Code (C++):
    Quelltext kopieren
    1. auto& myPolygons = myObj.getPolygons();
    2.  
    3. std::for_each(myPolygons.begin(), myPolygons.end(),
    4.                 [](Polygon& poly)
    5.                 {
    6.                     // mach was mit dem Polygon.
    7.                     // neu - brauchen jetzt auch die Normals!
    8.                 }
    9.             );
    10.  
    11. auto& myNormals = myObj.getSurfaceNormals(); // ...und jetzt??
    Jetzt muss man hingehen, und mühsam eine Schleife schreiben, die über beide Container drüber läuft, die Indices prüft, und den gewünschten Code auf jedes Objekt ausführt.

    Herkömmlicher Code würde das jetzt so machen. Advanced future supercode hingegen verwendet eine for_each Funktion, die es erlaubt, über mehrere Container/begin-end-Ranges gleichzeitig zu iterieren:

    Code (C++):
    Quelltext kopieren
    1. auto& myPolygons = myObj.getPolygons();
    2. auto& myNormals = myObj.getSurfaceNormals();
    3.  
    4. for_each_multiple([](Polygon& ply, Normal& nml)
    5.                 {
    6.                      // alles super!
    7.                 },
    8.                 myPolygons.begin(),
    9.                 myPolygons.end(),
    10.                 myNormals.begin(),
    11.                 myNormals.end()
    12.             );

    But wait! There's more!

    Dank variadic templates musste ich nur eine einzige Funktion schreiben (naja, eigentlich dann doch drei) für jede beliebige Anzahl von Containern/Iteratoren.

    Hier der Code, den ich gerne mal in clang und einem aktuellen VS compiliert hätte...
    Code (C++):
    Quelltext kopieren
    1. namespace detail
    2. {
    3.     struct stop_recursion{};
    4.  
    5.     template <typename Action, typename... Params>
    6.     bool for_each_multiple_impl(stop_recursion, Action action, Params&&... params)
    7.     {
    8.         action(std::forward<Params>(params)...);
    9.         return true;
    10.     }
    11.  
    12.     template <typename ForwardIterator, typename... OtherParams>
    13.     bool for_each_multiple_impl(ForwardIterator& first, const ForwardIterator& last, OtherParams&&... params)
    14.     {
    15.         if(first == last)
    16.             return false;
    17.  
    18.         bool othersReturn = for_each_multiple_impl(std::forward<OtherParams>(params)..., *first);
    19.         ++first;
    20.  
    21.         return true && othersReturn;
    22.     }
    23. }
    24.  
    25. ///as std::for_each, just that it iterates over multiple containers the same time and calls the action passed with the current element of each container. unfortunately, expects the action first, then the iterators.
    26. template <typename... Iters, typename Action>
    27. Action for_each_multiple(Action action, Iters... iters) //TODO enhance with a recursive decltype-determining function... get the last param of iters, -> this is our return type - then we can rearrange the order and have action last.
    28. {
    29.     //note that iters are taken by copy. we are referencing them from now on, and need a clean copy to work on.
    30.     bool succeeded = true;
    31.     auto recursionStopper = detail::stop_recursion();
    32.  
    33.     while(succeeded)
    34.         succeeded = detail::for_each_multiple_impl(iters..., recursionStopper, action);
    35.  
    36.     return std::move(action);
    37. }
    Und Code, mit dem man gleich bisschen testen kann:
    Code (C++):
    Quelltext kopieren
    1. auto action1 = [](int& val){std::cout << val << std::endl;};
    2. auto action2 = [](int& val1, int& val2){std::cout << val1 << ", " << val2 << std::endl;};
    3. auto action3 = [](int& val1, int& val2, int& val3){std::cout << val1 << ", " << val2 << ", " << val3 << std::endl;};
    4.  
    5. std::vector<int> vec1 = {1, 2, 3};
    6. std::vector<int> vec2 = {4, 5, 6};
    7. std::vector<int> vec3 = {7, 8, 9};
    8.  
    9. const auto beg1 = vec1.begin();
    10. const auto end1 = vec1.end();
    11. const auto beg2 = vec2.begin();
    12. const auto end2 = vec2.end();
    13. const auto beg3 = vec3.begin();
    14. const auto end3 = vec3.end();
    15.  
    16. for_each_multiple(action1, beg1, end1);
    17. for_each_multiple(action2, beg1, end1, beg2, end2);
    18. for_each_multiple(action3, beg1, end1, beg2, end2, beg3, end3);
    Sollte eine Ausgabe wie folgt produzieren:
    Code (Text):
    Quelltext kopieren
    1. 1
    2. 2
    3. 3
    4. 1, 4
    5. 2, 5
    6. 3, 6
    7. 1, 4, 7
    8. 2, 5, 8
    9. 3, 6, 9

    Gedanken? Ideen? Compilerfehler?
  2. coding-board

    coding-board Member

    Werbung
  3. German

    German Well-Known Member c-b Experte

    Hallo -AB-

    MinGW/GCC tut wie es soll, ebenso VS Express 2015. Beides unter Win10.
    Mit clang hab ich nur mal kurz experimentiert (noch unter Win7), aber irgendwie nicht geschafft es in eine IDE einzubinden. Somit kann ich dazu leider nicht sagen, sorry.

    EDIT
    Falls C-ler unterwegs sind, die clang installiert haben und -AB-s Codeschnipsel nicht zusammenfügen können, hier komplett mit Includes:
    Code (C++):
    Quelltext kopieren
    1. #include <iostream>
    2. #include <vector>
    3. #include <utility>
    4.  
    5. namespace detail
    6. {
    7.   struct stop_recursion {};
    8.  
    9.   template <typename Action, typename... Params>
    10.   bool for_each_multiple_impl(stop_recursion, Action action, Params&&... params)
    11.   {
    12.     action(std::forward<Params>(params)...);
    13.     return true;
    14.   }
    15.  
    16.   template <typename ForwardIterator, typename... OtherParams>
    17.   bool for_each_multiple_impl(ForwardIterator& first, const ForwardIterator& last, OtherParams&&... params)
    18.   {
    19.     if (first == last)
    20.       return false;
    21.  
    22.     bool othersReturn = for_each_multiple_impl(std::forward<OtherParams>(params)..., *first);
    23.     ++first;
    24.  
    25.     return true && othersReturn;
    26.   }
    27. }
    28.  
    29. ///as std::for_each, just that it iterates over multiple containers the same time and calls the action passed with the current element of each container. unfortunately, expects the action first, then the iterators.
    30. template <typename... Iters, typename Action>
    31. Action for_each_multiple(Action action, Iters... iters) //TODO enhance with a recursive decltype-determining function... get the last param of iters, -> this is our return type - then we can rearrange the order and have action last.
    32. {
    33.   //note that iters are taken by copy. we are referencing them from now on, and need a clean copy to work on.
    34.   bool succeeded = true;
    35.   auto recursionStopper = detail::stop_recursion();
    36.  
    37.   while (succeeded)
    38.     succeeded = detail::for_each_multiple_impl(iters..., recursionStopper, action);
    39.  
    40.   return std::move(action);
    41. }
    42.  
    43.  
    44. int main()
    45. {
    46.   auto action1 = [](int& val) {std::cout << val << std::endl; };
    47.   auto action2 = [](int& val1, int& val2) {std::cout << val1 << ", " << val2 << std::endl; };
    48.   auto action3 = [](int& val1, int& val2, int& val3) {std::cout << val1 << ", " << val2 << ", " << val3 << std::endl; };
    49.  
    50.   std::vector<int> vec1 = { 1, 2, 3 };
    51.   std::vector<int> vec2 = { 4, 5, 6 };
    52.   std::vector<int> vec3 = { 7, 8, 9 };
    53.  
    54.   const auto beg1 = vec1.begin();
    55.   const auto end1 = vec1.end();
    56.   const auto beg2 = vec2.begin();
    57.   const auto end2 = vec2.end();
    58.   const auto beg3 = vec3.begin();
    59.   const auto end3 = vec3.end();
    60.  
    61.   for_each_multiple(action1, beg1, end1);
    62.   for_each_multiple(action2, beg1, end1, beg2, end2);
    63.   for_each_multiple(action3, beg1, end1, beg2, end2, beg3, end3);
    64.  
    65.   return 0;
    66. }
    67.  
    Zuletzt bearbeitet: 22. August 2016
    Rockstar* gefällt das.
  4. lano

    lano Well-Known Member c-b Experte

    C-ler ?
    Von den mir bekannten hat der Eine die Frage gestellt und der Andere schon geantwortet :)

    @-AB- Codeschnipsel mal eben kurz... Das kann immer was werden. Besser nen kleines ... So wie German das gemacht hat ;)

    Bitte:
    Code (Text):
    Quelltext kopieren
    1. root@alien:/usr/src/test# clang++ -std=c++14 -pedantic -Wall test.c -o test -v      
    2. Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
    3. Target: i386-pc-linux-gnu
    4. Thread model: posix
    5. Found candidate GCC installation: /usr/bin/../lib/gcc/i586-linux-gnu/4.8
    6. Found candidate GCC installation: /usr/bin/../lib/gcc/i586-linux-gnu/4.8.4
    7. Found candidate GCC installation: /usr/bin/../lib/gcc/i586-linux-gnu/4.9
    8. Found candidate GCC installation: /usr/bin/../lib/gcc/i586-linux-gnu/4.9.2
    9. Found candidate GCC installation: /usr/lib/gcc/i586-linux-gnu/4.8
    10. Found candidate GCC installation: /usr/lib/gcc/i586-linux-gnu/4.8.4
    11. Found candidate GCC installation: /usr/lib/gcc/i586-linux-gnu/4.9
    12. Found candidate GCC installation: /usr/lib/gcc/i586-linux-gnu/4.9.2
    13. Selected GCC installation: /usr/bin/../lib/gcc/i586-linux-gnu/4.9
    14. Candidate multilib: .;@m32
    15. Selected multilib: .;@m32
    16. clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
    17. "/usr/lib/llvm-3.5/bin/clang" -cc1 -triple i386-pc-linux-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name test.c -mrelocation-model static -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu pentium4 -target-linker-version 2.25 -v -dwarf-column-info -resource-dir /usr/lib/llvm-3.5/bin/../lib/clang/3.5.0 -internal-isystem /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/c++/4.9 -internal-isystem /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/i386-linux-gnu/c++/4.9 -internal-isystem /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/i386-linux-gnu/c++/4.9 -internal-isystem /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/c++/4.9/backward -internal-isystem /usr/include/clang/3.5.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-3.5/bin/../lib/clang/3.5.0/include -internal-externc-isystem /usr/bin/../lib/gcc/i586-linux-gnu/4.9/include -internal-externc-isystem /usr/include/i386-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wall -pedantic -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /usr/src/test -ferror-limit 19 -fmessage-length 181 -mstackrealign -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -o /tmp/test-65409b.o -x c++ test.c
    18. clang -cc1 version 3.5.0 based upon LLVM 3.5.0 default target i386-pc-linux-gnu
    19. ignoring nonexistent directory "/include"
    20. ignoring duplicate directory "/usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/i386-linux-gnu/c++/4.9"
    21. ignoring duplicate directory "/usr/include/clang/3.5.0/include"
    22. #include "..." search starts here:
    23. #include <...> search starts here:
    24. /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/c++/4.9
    25. /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/i386-linux-gnu/c++/4.9
    26. /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../../include/c++/4.9/backward
    27. /usr/include/clang/3.5.0/include
    28. /usr/local/include
    29. /usr/bin/../lib/gcc/i586-linux-gnu/4.9/include
    30. /usr/include/i386-linux-gnu
    31. /usr/include
    32. End of search list.
    33. "/usr/bin/ld" --hash-style=both --build-id --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../i386-linux-gnu/crt1.o /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../i386-linux-gnu/crti.o /usr/bin/../lib/gcc/i586-linux-gnu/4.9/crtbegin.o -L/usr/bin/../lib/gcc/i586-linux-gnu/4.9 -L/usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../i386-linux-gnu -L/lib/i386-linux-gnu -L/usr/lib/i386-linux-gnu -L/usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../.. -L/usr/lib/llvm-3.5/bin/../lib -L/lib -L/usr/lib /tmp/test-65409b.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/bin/../lib/gcc/i586-linux-gnu/4.9/crtend.o /usr/bin/../lib/gcc/i586-linux-gnu/4.9/../../../i386-linux-gnu/crtn.o
    34. root@alien:/usr/src/test# ./test
    35. 1
    36. 2
    37. 3
    38. 1, 4
    39. 2, 5
    40. 3, 6
    41. 1, 4, 7
    42. 2, 5, 8
    43. 3, 6, 9
    44. root@alien:/usr/src/test#
  5. lano

    lano Well-Known Member c-b Experte

    Code (Text):
    Quelltext kopieren
    1. root@alien:/usr/src/test# g++ -std=c++11 test.c -o test
    2. root@alien:/usr/src/test# ./test
    3. 1
    4. 2
    5. 3
    6. 1, 4
    7. 2, 5
    8. 3, 6
    9. 1, 4, 7
    10. 2, 5, 8
    11. 3, 6, 9
    12. root@alien:/usr/src/test# g++ --version
    13. g++ (Debian 4.9.2-10) 4.9.2
    14. Copyright (C) 2014 Free Software Foundation, Inc.
    15. This is free software; see the source for copying conditions.  There is NO
    16. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    17.  
    Falls das auch von Interesse sein sollte
  6. -AB-

    -AB- Well-Known Member c-b Team

    Nein nein nein. Ich bin eindeutig kein C-ler. Wenn, dann ein C++er :)
    @AGGROStar1991 ist glaub ich hauptsächlich mit clang unterwegs und schwört auf dessen Fehlermeldungen. Und weil ich mindestens 3 Tage lang versucht hab, diese dumme Funktion zu schreiben, und letztendlich festhing, weil ich versucht habe, etwas umzusetzen, was mir GCC zwar hätte durchgehen lassen, clang aber (laut irgendwem im Internet) nicht, dachte ich mir, ich geh mal auf Nummer sicher...

    Aber danke euch beiden, dann klappts ja.
    Gedacht war der Code eigentlich für eine Ressource, da ist grad eh noch eine pending (geht auch ums iterieren...)
  7. German

    German Well-Known Member c-b Experte

    Du? :) Mir ging es da hauptsächlich um die Header, die ggf. unbekannt für jemand gewesen wären, der sich eher mit C beschäftigt.

    @-AB-
    Diese stop_recursion Klasse hat mich erst mal schön in's Grübeln versetzt ;) Coole Lösung.
    Was mir noch ein bisschen suspekt ist, ist diese "variadic template" Geschichte. Irgendwie musst du sicherstellen, dass du zusammengehörende Iteratoren übergibst.
    Sowas wie
    for_each_multiple(action1, beg1, end2);
    oder
    for_each_multiple(action1, beg1, beg2);
    rennt erst mal los, ohne dass Compiler oder Debugger meckern. Ich weiß nicht ob dein TODO das abfedert, oder ob du überhaupt vorhast da ranzugehen...
    Zuletzt bearbeitet: 22. August 2016
  8. lano

    lano Well-Known Member c-b Experte

    Ohh, ich wollt dich nicht beleidigen...
    Wie jetzt? Nur weil ich nen HalloWelt fehlerfrei zusammen bekomme gibts gleich Schulterklappen?
    Dem Rang kann ich nicht gerecht werden.
  9. -AB-

    -AB- Well-Known Member c-b Team

    Mhh, Notlösung. Ich hab es erst ohne versucht - hatte gehofft, da ich ja die Action übergebe könnte er das matchen (in einem Fall Action und "Zeugs dahinter", im anderen Fall "2 Iteratoren und Zeugs") - geht leider aber nicht.

    Also so den fixen Punkt erzwungen, an welcher Stelle er die Rekursion abbrechen, und das "Zeugs" als Parameter für die Action werten soll. In C++17 sollte es auch soweit ich mich erinnere eine Art std::is_callable geben, was true für einen Funktor oder Funktionspointer übergibt; damit wäre das Problem dann auch gelöst.

    Also, bei deinem Beispiel kann man leider nicht viel machen. Aber auch ein normales std::for_each mit zwei Iteratoren von unterschiedlichen Containern produziert einfach undefiniertes Verhalten...

    Man könnte am Anfang die Anzahl der Parameter testen, ob sie ungerade ist, bzw: generell an den Fehlermeldungen arbeiten. Das TODO ist nur, um die Reihenfolge der Parameter zu ändern - std::for_each will erst die Parameter, dann die Action - wenn ich das als Parameter Pack reingebe, hab ich aber nicht den Typen des letzten Elements. Da müsste man aber ne relativ einfache Rekursion für schreiben können, die über das Pack drüber läuft und den letzten Typen returned. (Ich brauch den Typen für den Rückgabewert, da ja eine Action zurückgegeben wird... Die STL machts so, also mach ich das auch.)

    Eine Fehlermeldung gibts momentan leider auch nur irgendwo tief genestet, "kann keinen passenden Overload finden" - wenn man z.B. einen Parameter vergisst. Mit einem Check, dass eine ungerade Anzahl Parameter (also gerade Anzahl Iteratoren + Funktion) übergeben wurden, ist die Sache vielleicht etwas klarer. Immerhin *müssen* beides Iteratoren sein, sonst hängts schon am std::enable_if :)
  10. German

    German Well-Known Member c-b Experte

    Ein bisschen mehr war es schon, soweit ich mich erinnere :)

    OK, das Beispiel war zwar einfach aber nicht besonders sinnreich. Klar, wenn du nur ein Paar begin und end Iteratoren hast, ist die Gefahr (ebenso wie bei std::for_each) nicht besonders groß. Bei zwei Paaren könnte schon jemand auf andere Ideen, wie
    for_each_multiple(action2, beg1, beg2, end1, end2);
    kommen. Mit vielen Argumenten wird das schnell unübersichtlich. Auf Anhieb wäre mir eingefallen, die Container als Referenz zu übergeben, statt die Iteratoren. Allerdings hat das auch ohne zu Ende gedacht zu haben den Nachteil, dass du dich um die Möglichkeit beschneidest, nur über Teilbereiche der Container zu iterieren :confused: Also wohl keine Überlegung wert ...
Die Seite wird geladen...
Ähnliche Themen - clang gleichzeitig mehrere Forum Datum
Unterschiedliche Adressen "gleichzeitig" anpingen .NET Technology 8. Februar 2014
Kann man eine MySQL-Datenbank für mehrere Sachen gleichzeitig verwenden? HTML und CSS 8. Februar 2013
[x86 Real] Mehrere tastendrücke gleichzeitig Assembler (ASM) 31. Oktober 2012
Mehrere Skripte gleichzeitig laufen lassen.... Visual Basic, Visual Basic for Applications (VBA) 27. September 2010
Visual Basic - 2 TextBoxen gleichzeitig scrollen .NET Technology 12. Januar 2010