Java Umsteiger benötigt Hilfe bei "For-Each" Schleife



  • Hallo,

    ich möchte eine Methode schreiben, die alle Elemente eines Int Arrays zusammenzählt. Dazu wollte ich einfach das Array übergeben, und jedes Element auf eine counter Variable addieren.

    Verwendet habe ich dafür eine For schleife ohne Index

    int count(int myarray[]){
            int counter=0;
    	//int size = sizeof(myarray)/sizeof(myarray[0]);
    	for(int i : myarray){
                    counter+=i;
    		}
    
    	return counter;
    	}
    

    im Schleifenkopf bekomme ich die schöne Meldung

    Error:diese bereichsbasierte "For" Anweisung erfordert eine geeignete begin-Funktion, die jedoch nicht gefunden wurde

    Warum kann ich diese Schleifenvariante hier nicht verwenden?

    MfG



  • int myarray[]
    

    ist in Wirklichkeit sowas:

    int* myarray
    

    D.h. du hast ein rohes Array, dessen Laenge zu diesem Zeitpunkt unbekannt ist.
    Loesung:
    a) Laenge uebergeben
    b) Container von C++ wie std::vector<int> nutzen

    Auch folgendes wird nicht funktionieren:

    int size = sizeof(myarray)/sizeof(myarray[0]);
    

    myarray ist ein Pointer und ist entweder 64 oder 32 Bit gross (4 oder 8 Byte).


  • Mod

    knivil schrieb:

    Loesung:
    a) Laenge uebergeben
    b) Container von C++ wie std::vector<int> nutzen

    c) Iteratoren benutzen, das klappt immer und universell mit allen Arten von Containern
    d) std::accumulate :p (aber nur wenn es bloß um das Funktionieren geht, nicht um das Lernen)



  • knivil schrieb:

    int myarray[]
    

    ist in Wirklichkeit sowas:

    int* myarray
    

    Stopp mal! Wenn ich das sage, gehen alle auf mich los, aber wenn er das sagt ist das in Ordnung?!
    Edit: Ups, es geht ja um dieses Konstrukt mit dem leeren Klammerpaar, das ist was anderes. Bin schon still.



  • Sone, ob das Klammerpaar in diesem Kontext leer ist oder eine Ganzzahlkonstante enhält, spielt überhaupt keine Rolle.

    http://c-faq.com/aryptr/aryparmsize.html


  • Mod

    Sone schrieb:

    Ups, es geht ja um dieses Konstrukt mit dem leeren Klammerpaar, das ist was anderes.

    Es geht um die Deklaration eines Funktionsparameters.



  • Ist mir klar, dass es um Funktionsparameter geht. Wo sonst (außer bei List-Initialisierung) kann wohl das Klammerpaar leer sein? (Und ja, mir ist auch klar dass es bei Funktionsparametern keine Rolle spielt)
    Edit: Naja, streng genommen natürlich bei parameter-declarations.


  • Mod

    Sone schrieb:

    Wo sonst (außer bei List-Initialisierung) kann wohl das Klammerpaar leer sein?

    extern char data[];
    


  • camper schrieb:

    extern char data[];
    

    Oh? Was soll das sein? Und was bestimmt sizeof(data) ? Wird dann data auch ein Zeiger?
    Kannte ich gar nicht. Sieht komisch aus.

    Edit:

    Furthermore, if there is a preceding declaration
    of the entity in the same scope in which the bound was specified, an omitted array bound is taken to be the
    same as in that earlier declaration, and similarly for the definition of a static data member of a class.

    ?


  • Mod

    Sone schrieb:

    camper schrieb:

    extern char data[];
    

    Oh? Was soll das sein? Und was bestimmt sizeof(data) ? Wird dann data auch ein Zeiger?
    Kannte ich gar nicht. Sieht komisch aus.

    Das ist ein Array mit unbestimmter Größe. Der Typ ist unvollständig (folglich kann sizeof darauf nicht angewendet werden).
    Über

    struct foo;
    extern foo bar;
    

    wunderst du dich doch auch nicht?
    oder wenn das extern stöhrt:

    struct foo
    {
        static char some_data[];
        static foo proto;
    };
    


  • static char some_data[];
        static foo proto;
    

    Ne, die kenn' ich schon lang. Auch das andere Beispiel ist bekannt.
    Ich hatte da einen Denkfehler. Also war das von mir verlinkte Zitat richtig; die Variable muss noch einmal mit Array-Bounds deklariert werden, um sie dann nutzen zu können. (richtig?)


  • Mod

    Sone schrieb:

    static char some_data[];
        static foo proto;
    

    Ne, die kenn' ich schon lang. Auch das andere Beispiel ist bekannt.
    Ich hatte da einen Denkfehler. Also war das von mir verlinkte Zitat richtig; die Variable muss noch einmal mit Array-Bounds deklariert werden, um sie dann nutzen zu können. (richtig?)

    Wie bei anderen Variablen auch müssen Arrays, sofern sie (odr-) benutzt werden im Programm auch definiert werden. Die obigen Codebeispiele sind keine Definitionen.
    Die Definition eines Objektes erfordert, dass der Typ des zu definierenden Objektes an dieser Stelle vollständig ist, mit der speziellen Ausnahme, dass im Falle von Arrays auch eine unbestimmte Größe angegeben werden darf, wenn die tatsächliche Größe aus dem Initialisierer bestimmt werden kann.

    Die zitierte Aussage ist aus einem anderen Grund wichtig. Im Gegensatz zu dem Fall, das ein Klasseobjekt zunächst mit einer noch nicht vollständigen Klasse deklariert und erst später definiert wird, führt die spätere Definition eines Arrays, dass in der ursprünglichen Deklaration noch unbestimmte Größe hat, dazu, dass sich der Typ des deklarierten Objektes ändert (von Array unbestimmter Größte aus T zu Array mit Größe X aus T). Das würde ohne die zitierte Stelle ill-formed sein (alle Deklarationen eines Objektes im selben Scope müssen schließlich eigentlich den gleichen Typ haben). Das führt dann nat. auch dazu, dass man so ganz unbemerkt die ODR verletzen kann, z.B. wenn das Array für die Bestimmung eines Templateparameters herangezogen wird.

    Edit: Beispiel entfernt, war nicht ganz passend.

    Das führt mich zu einem weiteren Beispiel:
    unique_ptr<T[]> hast du bestimmt auch schon gesehen.



  • ...



  • Ich dachte, es gibt überhaupt nicht sowas wie einen unvollständigen Array-Typen, sondern nur vollständige mit einer festen Größe. Jetzt weiß ich es besser. Vielen Dank für die Erklärung. 👍
    Shame on me -

    Swordfish schrieb:

    once again.

    Eine Frage noch - ist dann dieser Array-Typ ohne Größenangabe ein opaker Datentyp? Nein, oder? Man kann es ja ganz gewöhnlich benutzen, nur mit der Ausnahme das man bspw. die Größe nicht bekommen kann da der Typ ja noch nicht bekannt ist.



  • Das heißt, is_array muss auch eine Spezialisierung für alle solche unvollständigen Array-Typen haben:

    template<typename T> struct is_array : std::false_type {};
    template<typename T, std::size_t N> struct is_array<T[N]> : std::true_type {};
    template<typename T> struct is_array<T[]> : std::true_type {};
    

    💡 💡

    Edit: Nah, mir fällt gerade ein- die Type-Traits leiten ja einfach von std::integral_constant ab.


  • Mod

    Sone schrieb:

    Das heißt, is_array muss auch eine Spezialisierung für alle solche unvollständigen Array-Typen haben:

    genau. Wird aber offensichtlich selten gebraucht.

    Habe mal aus dem meinem Archiv einen type printer hevorgekramt (finde Thread nicht mehr, muss irgendwann in 2011 gewesen sein), damit kann man es auch schön demonstrieren:

    #include <string>
    #include <iostream>
    #include <utility>
    #include <type_traits>
    #include <boost/mpl/pair.hpp>
    #include <boost/mpl/map.hpp>
    #include <boost/mpl/at.hpp>
    #include <boost/mpl/if.hpp>
    #include <boost/mpl/has_key.hpp>
    #include <boost/mpl/insert.hpp>
    
    template <char... c> struct literal
    {
        static constexpr char str[sizeof...( c ) + 1] = { c... };
        typedef literal type;
    };
    template <char... c>
    constexpr char literal<c...>::str[];
    
    template <typename... s> struct concat
        : concat<typename s::type...> {};
    template <char... c1, char... c2, typename... s> struct concat<literal<c1...>,literal<c2...>, s...>
        : concat<literal<c1..., c2...>, s...> {};
    template <char... c> struct concat<literal<c...>>
        : literal<c...> {};
    template <> struct concat<>
        : literal<> {};
    
    template <std::size_t N, typename L = literal<>> struct N_to_literal
        : N_to_literal<N / 10, concat<literal<('0' + N % 10)>,L>> {};
    template <typename L> struct N_to_literal<0, L>
        : L {};
    template <> struct N_to_literal<0, literal<>>
        : literal<'0'> {};
    
    typedef boost::mpl::map<
        boost::mpl::pair<void,               literal<'v','o','i','d'>>,
        boost::mpl::pair<char,               literal<'c','h','a','r'>>,
        boost::mpl::pair<signed char,        literal<'s','i','g','n','e','d',' ','c','h','a','r'>>,
        boost::mpl::pair<unsigned char,      literal<'u','n','s','i','g','n','e','d',' ','c','h','a','r'>>,
        boost::mpl::pair<short,              literal<'s','h','o','r','t'>>,
        boost::mpl::pair<unsigned short,     literal<'u','n','s','i','g','n','e','d',' ','s','h','o','r','t'>>,
        boost::mpl::pair<int,                literal<'i','n','t'>>,
        boost::mpl::pair<unsigned,           literal<'u','n','s','i','g','n','e','d'>>,
        boost::mpl::pair<long,               literal<'l','o','n','g'>>,
        boost::mpl::pair<unsigned long,      literal<'u','n','s','i','g','n','e','d',' ','l','o','n','g'>>,
        boost::mpl::pair<long long,          literal<'l','o','n','g',' ','l','o','n','g'>>,
        boost::mpl::pair<unsigned long long, literal<'u','n','s','i','g','n','e','d',' ','l','o','n','g',' ','l','o','n','g'>>,
        boost::mpl::pair<wchar_t,            literal<'w','c','h','a','r','_','t'>>,
        boost::mpl::pair<char16_t,           literal<'c','h','a','r','1','6','_','t'>>,
        boost::mpl::pair<char32_t,           literal<'c','h','a','r','3','2','_','t'>>,
        boost::mpl::pair<float,              literal<'f','l','o','a','t'>>,
        boost::mpl::pair<double,             literal<'d','o','u','b','l','e'>>,
        boost::mpl::pair<long double,        literal<'l','o','n','g',' ','d','o','u','b','l','e'>>,
        boost::mpl::pair<std::nullptr_t,     literal<'s','t','d',':',':','n','u','l','l','p','t','r','_','t'>>> fundamental_types;
    
    template <typename L, typename R, bool b> struct type_name_parts
    {
        typedef L left;
        typedef R right;
        static constexpr bool right_last = b;
    };
    
    template <typename T, typename M> struct derive_name_parts;
    
    template <typename T, typename M = fundamental_types> struct type_name
        : concat<typename derive_name_parts<T, M>::left, typename derive_name_parts<T, M>::right> {};
    
    template <typename P, typename S> struct derive_left
        : type_name_parts<
            concat<typename P::left, boost::mpl::if_c<P::right_last, literal<'('>, literal<>>, S>,
            concat<boost::mpl::if_c<P::right_last, literal<')'>, literal<>>, typename P::right>,
            false> {};
    
    template <typename P, typename S> struct derive_right
        : type_name_parts<typename P::left, concat<S, typename P::right>, true> {};
    
    template <typename P, typename S> struct mem_fun_suffix
        : type_name_parts<typename P::left, concat<typename P::right, S>, true> {};
    
    template <typename M, typename...> struct pretty_args;
    template <typename M> struct pretty_args<M>
        : literal<> {};
    template <typename M, typename T> struct pretty_args<M, T>
        : type_name<T, M> {};
    template <typename M, typename T, typename... Args> struct pretty_args<M, T, Args...>
        : concat<pretty_args<M, T>,literal<','>, pretty_args<M, Args...>> {};
    
    template <typename T, typename M> struct derive_name_parts
        : type_name_parts<boost::mpl::if_<boost::mpl::has_key<M, T>, boost::mpl::at<M, T>, literal<'u','n','k','n','o','w','n'>>, literal<>, false> {};
    
    template <typename T, typename M> struct derive_name_parts<const T, M>
        : derive_left<derive_name_parts<T, M>, literal<' ','c','o','n','s','t'>> {};
    template <typename T, typename M> struct derive_name_parts<volatile T, M>
        : derive_left<derive_name_parts<T, M>, literal<' ','v','o','l','a','t','i','l','e'>> {};
    template <typename T, typename M> struct derive_name_parts<const volatile T, M>
        : derive_left<derive_name_parts<T, M>, literal<' ','c','o','n','s','t',' ','v','o','l','a','t','i','l','e'>> {};
    template <typename T, typename M> struct derive_name_parts<T*, M>
        : derive_left<derive_name_parts<T, M>, literal<'*'>> {};
    template <typename T, typename M> struct derive_name_parts<T&, M>
        : derive_left<derive_name_parts<T, M>, literal<'&'>> {};
    template <typename T, typename M> struct derive_name_parts<T&&, M>
        : derive_left<derive_name_parts<T, M>, literal<'&','&'>> {};
    template <typename T, typename M, std::size_t N> struct derive_name_parts<T[N], M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'['>,N_to_literal<N>,literal<']'>>> {};
    template <typename T, typename M> struct derive_name_parts<T[], M>
        : derive_right<derive_name_parts<T, M>, literal<'[',']'>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...), M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','c','o','n','s','t'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) volatile, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','v','o','l','a','t','i','l','e'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const volatile, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','c','o','n','s','t',' ','v','o','l','a','t','i','l','e'>>> {};
    // again...
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) &, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','&'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const &, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','c','o','n','s','t',' ','&'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) volatile &, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','v','o','l','a','t','i','l','e',' ','&'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const volatile &, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','c','o','n','s','t',' ','v','o','l','a','t','i','l','e',' ','&'>>> {};
    // yet again...
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) &&, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','&','&'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const &&, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','c','o','n','s','t',' ','&','&'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) volatile &&, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','v','o','l','a','t','i','l','e',' ','&','&'>>> {};
    template <typename T, typename M, typename... Args> struct derive_name_parts<T(Args...) const volatile &&, M>
        : derive_right<derive_name_parts<T, M>, concat<literal<'('>, pretty_args<M, Args...>, literal<')',' ','c','o','n','s','t',' ','v','o','l','a','t','i','l','e',' ','&','&'>>> {};
    //
    template <typename T, typename M, typename C> struct derive_name_parts<T C::*, M>
        : derive_left<derive_name_parts<T, M>, concat<literal<' '>, type_name<C, M>, literal<':',':','*'>>> {};
    
    int main()
    {
        struct Foo;
        std::cout << type_name<int>::type::str << '\n';
        std::cout << type_name<int const>::type::str << '\n';
        std::cout << type_name<int*>::type::str << '\n';
        std::cout << type_name<int&&>::type::str << '\n';
        std::cout << type_name<int[]>::type::str << '\n';
        std::cout << type_name<int(void)>::type::str << '\n';
        std::cout << type_name<int(*)[12345]>::type::str << '\n';
        std::cout << type_name<void(int)>::type::str << '\n';
        std::cout << type_name<int&(int*, char)>::type::str << '\n';
        std::cout << type_name<int&(int*, char, int&(*&)(long,long long))>::type::str << '\n';
        std::cout << type_name<Foo>::type::str << '\n';
        std::cout << type_name<int Foo::*>::type::str << '\n';
        std::cout << type_name<int (Foo::*)()>::type::str << '\n';
        std::cout << type_name<int (Foo::*)(int, char)const volatile>::type::str << '\n';
    
        typedef boost::mpl::insert<
            boost::mpl::insert<fundamental_types, boost::mpl::pair<Foo, literal<'F','o','o'>>>::type,
            boost::mpl::pair<std::string, literal<':',':','s','t','d',':',':','s','t','r','i','n','g'>>>::type more_types;
        std::cout << type_name<Foo, more_types>::type::str << '\n';
        std::cout << type_name<int Foo::*, more_types>::type::str << '\n';
        std::cout << type_name<int (Foo::*)(), more_types>::type::str << '\n';
        std::cout << type_name<int (Foo::*)()&, more_types>::type::str << '\n';
        std::cout << type_name<std::string (Foo::*)(int, char)const volatile, more_types>::type::str << '\n';
    }
    

    ideone hat leider kein boost



  • Das sieht ja geil aus.
    Wobei das bei mir nicht kompiliert, offensichtlich hat mein Compiler wohl einen Bug:

    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|117|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|119|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|121|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|123|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|126|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|128|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|130|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|132|error: wrong number of template arguments (1, should be 2)|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|64|error: provided for 'template<class T, class M> struct derive_name_parts'|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx||In function 'int main()':|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|162|error: template argument 1 is invalid|
    C:\Programming\C++\Saves\TEMPS\TEMP.cxx|162|error: '<expression error>::type' has not been declared|
    

    (MinGW GCC 4.8, Boost 1.53)



  • Btw, hier der Thread http://www.c-plusplus.net/forum/290867-full
    Ein Gott bleibt ein Gott.

    Edit: Ich setz' mich ganz kurz mal ran, und schau, was bei mir rauskommt. Die MPL beherrsche ich leider nicht.


  • Mod

    Bug. g++ kommt offenbar nicht mit ref-Qualifizierer als Teil des Funktionstyps zurecht. g++-4.8 bringt den selben Fehler, 4.9 alpha bringt nur noch 4 Fehler (in den Zeilen, in denen ein Ref-Qualifizierer aber kein cv-Q. auftritt).
    clang schluckt es anstandslos.



  • 4.9 alpha bringt nur noch 4 Fehler

    Wo hast du das her?
    Edit: Es ist doch noch nicht einmal 4.8.1 raus..


Anmelden zum Antworten