Java Umsteiger benötigt Hilfe bei "For-Each" Schleife
-
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.
-
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 danndataauch 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.?
-
Sone schrieb:
camper schrieb:
extern char data[];Oh? Was soll das sein? Und was bestimmt
sizeof(data)? Wird danndataauch 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).
Überstruct 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?)
-
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_arraymuss 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_constantab.
-
Sone schrieb:
Das heißt,
is_arraymuss 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.
-
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..
-
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.
-
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 ... ?
-
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