campers TMP-Aufgabe(n): 7
-
Ein constexpr kann problemlos hinzugefügt werden
template <int... i, int... j> constexpr const int acc<index_list<i...>, index_list<j...>>::value = acc().rack<sizeof...(j)-1>::v;So oder so kann v dann in konstanten Ausdrücken verwendet werden.
Mit dem Array funktioniert das nicht (wobei ich den Standard an dieser Stelle für unklar halte).
-
template <int... i, int... j> constexpr const int acc<index_list<i...>, index_list<j...>>::valueWas ist das? oO Wie soll das gehen?
Edit: Das geht doch überhaupt nicht!
Aber du hast Recht, v ist constexpr.
-
Sone schrieb:
Aber du hast Recht, v ist
constexpr.Nö, auch das nicht!
note: 'constexpr acc<index_list<i ...>, index_list<j ...> >::acc() [with int ...i = {1, 2, 3}; int ...j = {0, 1, 2}]' is not usable as a constexpr function because:|(Es folgt nichts)
Kann auch ein Bug sein. Ist der GCC 4.8.1...Nach GCC 4.8.1 jedenfalls ist deine Lösung nicht statischer als meine. Auch meine lässt sich als Array-Bound verwenden, nicht aber als initializer für eine
constexpr-Variable.
-
Ich betrachte das mal als Bug (von gcc).
Der entscheidene Test sollte sein, ob nach der Definition value als konstanter Ausdruck verwendet werden kann.constexpr int foo = accumulate<list>::value;extern const int foo; constexpr int foo = 42;ist legal (und sowieso die einzige Möglichkeit, da constexpr immer einen Initialisierer benötigt, liese sich eine solche Variable sonst gar nicht nur deklarieren).
-
Die Map:
enum class lookup_mode { FirstSec, SecFirst }; template <lookup_mode lk, int, typename T, typename, typename = typename make_index_list<T::size>::type> struct lookup; template <lookup_mode lk, int key, int... first, int ... second, int... indices> struct lookup<lk, key, index_list<first...>, index_list<second...>, index_list<indices...>>: rack<-1>, rack<indices>... { constexpr lookup() : rack<-1>{0}, rack<indices>{ ( rack<indices-1>::v ? 0 : ( lk == lookup_mode::FirstSec ? (first == key) * second : (second == key) * first ) ) + rack<indices-1>::v } ... {} static const int value; }; template <lookup_mode lk, int val, int... i, int ... k, int... indices> const int lookup<lk, val, index_list<i...>, index_list<k...>, index_list<indices...>>::value = lookup{}.rack<sizeof...(indices)-1>::v; int main() { std::cout << lookup<lookup_mode::FirstSec, 8, index_list<4, 8, 6>, index_list<0, 47, 95>>::value << '\n'; std::cout << lookup<lookup_mode::SecFirst, 6, index_list<4, 74, 68, 6>, index_list<0, 6, 6, 95>>::value << '\n'; }Auch hier wäre deine Idee von typedefs mit template-parameter packs schön, das würde besser passen.
using pack_typedef_name = ... std::conditional< lk == lookup_mode::FirstSec, tpp_wrapper<first...>, tpp_wrapper<second...> >::type::pack;(Die Ellipse gibt an, dass pack ein parameter-pack ist)
camper schrieb:
(und sowieso die einzige Möglichkeit, da constexpr immer einen Initialisierer benötigt, liese sich eine solche Variable sonst gar nicht nur deklarieren).
Aber schon, wenn sie eine statische Membervariable ist (wie ja auch in [dcl.constexpr]/1 erklärt). Das implementiert aber GCC 4.8.1 nicht korrekt...
-
template <int Key, bool Flipped=false> struct hook { int value; }; template <typename, typename> struct static_map; template <int... first, int ... second> struct static_map<index_list<first...>, index_list<second...> > : hook<first>..., hook<second, true>... { static_map() : hook<first>{second}..., hook<second, true>{first}... {} template <int V> static constexpr int lookup_key() { return static_cast<hook<V> >(static_map{}).value; } template <int V> static constexpr int lookup_value() { return static_cast<hook<V, true> >(static_map{}).value; } };
-
Sone schrieb:
camper schrieb:
(und sowieso die einzige Möglichkeit, da constexpr immer einen Initialisierer benötigt, liese sich eine solche Variable sonst gar nicht nur deklarieren).
Aber schon, wenn sie eine statische Membervariable ist (wie ja auch in [dcl.constexpr]/1 erklärt).
Was wird da erklärt?
9.4.2/3
...
A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression.
-
Das Problem mit dem Array lässt sich auf diesen Fall reduzieren
struct A { int x,y; constexpr A() : x{y}, y{x} {} }; constexpr A a{}; // ok, da zuerst Zero-Initialisierung constexpr int foo[] = { foo[0] }; constexpr int bar[] = { 0, bar[0] };Die Definition von z wird akzeptiert, die von foo und bar von clang nicht (und g++ streikt sowieso).
Meiner Ansicht nach haben beide Compiler unrecht:n3337 schrieb:
A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [ Note: An overloaded operator invokes a function.—end note ]:
...
— an lvalue-to-rvalue conversion (4.1) unless it is applied to
____— a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
____— a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
____— a glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not ended, initialized with a constant expression;
...Der markierte Teil trifft hier auf beide Fälle zu. Insbesondere wird nicht verlangt, dass die Initialisierung bereits abgeschlossen ist.
struct foo { static constexpr int x[] = { x[0] }; }; const int foo::x[];kann hingegen nicht funktionieren, denn die Deklaration in der Klasse ist keine Definition.
-
denn die Deklaration in der Klasse ist keine Definition.
Jetzt bin ich völlig verwirrt.
Damit ist das in der Klasse aber keine Initialisierung...
P.S.: Arch-Linux ist drauf. Ist voll toll.

(Außer das irgendwie GNOME nicht richtig die Programme startet, muss immer in der Konsole thunderbird schreiben... aber dafür gibt es ja Skripte)
-
Sone schrieb:
denn die Deklaration in der Klasse ist keine Definition.
Jetzt bin ich völlig verwirrt.
static data member werden in der Klassendefinition bloß deklariert, nicht definiert; das ist nichts Neues (gerade deshalb muss ja oft (=odr-use) zusätzlich eine Definition ausserhalb der Klassendefinition erfolgen).
Die zitierte Regel stellt aber ausdrücklich auf die Definition ab
____— a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
-
Ok, ich habe wieder einen klaren Kopf:
A declaration is a definition unless [...] it declares a static data member in a class definition
Somit kann das keine Definition sein.
Edit: Das steht auch nochmal oben von dir, verzeih'.constexpr const int* xp = addr(x);// OK:(const int*)&(const int&)x is an address constant expressionMOMENT MAL! Davon wusste ich nichts...
Bzw. das müsste ich eigentlich - ich hab bei camper schon Memberfunktions-Zeiger als Template-Parameter gesehen...
Das ist interessant. Sehr interessant.camper schrieb:
Meiner Ansicht nach haben beide Compiler unrecht:
n3337 schrieb:
A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [ Note: An overloaded operator invokes a function.—end note ]:
...
— an lvalue-to-rvalue conversion (4.1) unless it is applied to
____— a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
____— a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
____— a glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not ended, initialized with a constant expression;
...Der markierte Teil trifft hier auf beide Fälle zu. Insbesondere wird nicht verlangt, dass die Initialisierung bereits abgeschlossen ist.
Natürlich nicht. Denn hier ist die Deklaration eine Definition ([basic.def]/2) und der Punkt der Deklaration (point of declaration) ist ja vor dem Initializer, hier die initializer-list. Damit sollte das doch gehen, nicht wahr?
Edit: Jaja, das war gerade falsch - Standard falsch gelesen.Und
foo[0]ist dann was? Oder hat der Standard dafür wieder ein kleines Hintertürchen?
-
Sone schrieb:
Und
foo[0]ist dann was?Ein lvalue, dass auf das erste Element des Arrays verweist (und ein konstanter Ausdruck: foo[0] ist *(foo+0) - die array-to-pointer-Konvertierung ist konstant, weil sie auf ein Objekt mit statischer Speicherdauer verweist, 0 ist ein Literal und + und * sind nicht in der Liste der Ausnahmen enthalten, also unproblematisch; Problematisch könnte also nur die finale Umwandlung des lvalues foo[0] in ein rvalue sein).