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



  • 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..


  • Mod

    Sone schrieb:

    Wo hast du das her?

    svn-Snapshots.

    Aus Bequemlichkeit verwende ich Gentoos toolchain-Overlay.

    Sieht so aus, als ob wir mit C++1y einen neuen Arraytyp (of runtime bound) bekommen.


  • Mod

    Habe mal den boost-Teil entfernt und die problematischen Stellen mit einem #ifdef versehen. So läuft es auch auf ideone



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

    Dachte, dass unvollstaendige Typen keine Templateparameter sein koennen ... ?


  • Mod

    knivil schrieb:

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

    Dachte, dass unvollstaendige Typen keine Templateparameter sein koennen ... ?

    Können schon. Nur führt das bei Templates der Standardbibliothek zu undefiniertem verhalten, es sei denn, die betreffende Komponente der Standardbibliothek macht explizit eine Ausnahme. Für (einige) type_traits ist das der Fall.



  • knivil schrieb:

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

    Dachte, dass unvollstaendige Typen keine Templateparameter sein koennen ... ?

    Das Zitat hab' ich schon vor einer Weile gepostet - erinnerst du dich?

    Sone schrieb:

    JETZT hab ich dich!

    [temp.arg.type]/2 schrieb:

    A template type argument may be an incomplete type


  • Mod

    kleines Update: gcc-4.8.1 und ein aktueller 4.9er-Snapshot kommen mit meinem Code ohne Probleme zurecht.
    und 4.8 erzeugt auch bessere Fehlermeldungen


Anmelden zum Antworten