Forum: Compiler & IDEs [C++] constexpr Funktion => Arraygrösse in Klasse


von B. S. (bestucki)


Lesenswert?

Hallo zusammen

Ich habe folgendes Minimalbeispiel erstellt:
1
#include <array>
2
#include <cstddef>
3
4
static constexpr std::size_t SizeA() noexcept {return 128;}
5
6
class myclass{
7
  public:
8
    static constexpr std::size_t SizeB() noexcept {return 128;}
9
  private:
10
    std::array<int, SizeA()> FieldA_; // kompiliert
11
    std::array<int, SizeB()> FieldB_; // kompiliert nicht
12
      // error: ‘static constexpr std::size_t myclass::SizeB()’ called in a constant expression
13
      // note: in template argument for type ‘unsigned int’
14
};
15
16
int main(){
17
  std::array<int, SizeA()> FieldA;          // kompiliert
18
  std::array<int, myclass::SizeB()> FieldB; // kompiliert
19
  
20
  return 0;
21
}

Das Problem ist nun, dass ich genau das machen will, das scheinbar nicht 
möglich ist. Warum ist das so und was sind gute Alternativen?

Ich könnte auch direkt
1
std::array<int, 128>
schreiben, jedoch benötige ich den Wert an mehreren Orten und möchte 
genau das vermeiden.

Compiler: GCC 4.8.2
Sprache:  C++11

Vielen Dank für eure Hilfe!

von Peter II (Gast)


Lesenswert?

für so etwas bietet sich doch an ein template zu schreiben.

von Dr. Sommer (Gast)


Lesenswert?

Aus dem C++ Standard:

A class is considered a completely-defined object type at the closing } 
of the class-specifier. Within the class member-specification, the class 
is regarded as complete within function bodies, [...] Otherwise it is 
regarded as incomplete within its own class member-specification.

Das heißt es wird erst der Inhalt deiner Klasse ausgewertet, und dann 
erst der Body von SizeB. Aber dann ist es schon zu spät, denn die Größe 
von FieldB_ muss dann schon bekannt sein. Umgekehrt würde es also 
funktionieren, d.h. aus dem Body von SizeB auf FieldB_ zuzugreifen.

Du könntest aus SizeB eine statische member-Variable machen oder eine 
globale Funktion.

von rmu (Gast)


Lesenswert?

be stucki schrieb:
> Ich könnte auch direktstd::array<int, 128>schreiben, jedoch benötige ich
> den Wert an mehreren Orten und möchte
> genau das vermeiden.
>
> Compiler: GCC 4.8.2
> Sprache:  C++11

mach ein enum oder ein static constexpr int.

von B. S. (bestucki)


Lesenswert?

Danke für die Antworten! Dass der Inhalt von Funtionen erst nach dem 
abschliessenden } ausgewertet wird, wusste ich nicht. Habe jetzt die 
Funktion durch eine statische Membervariable ersetzt.

von Leo B. (luigi)


Lesenswert?

Ich gebe zu, ich sehe solch ein Konstrukt zum ersten mal, aber gibt es 
hierfür nicht das gute alte #define?
Nur weil das alt ist, ist es ja nicht schlecht?!

von Dr. Sommer (Gast)


Lesenswert?

Leo B. schrieb:
> Ich gebe zu, ich sehe solch ein Konstrukt zum ersten mal, aber gibt es
> hierfür nicht das gute alte #define?
> Nur weil das alt ist, ist es ja nicht schlecht?!
Präprozessor-Makros haben diverse Nachteile, aber leider werden sie 
immernoch unnötigerweise oft für Dinge wie Integer-Konstanten verwendet.

Makros sind eine dumme Textersetzung, die subtilere Dinge der Sprache 
wie Typen und Scopes völlig außer Acht lässt. Hat man einmal ein Makro 
definiert, kann man diesen Namen nie wieder im Projekt verwenden, auch 
nicht in inneren Scopes wie Funktionen. Macht man es versehentlich doch, 
weil man den Überblich über alle seine Macros sowie die aller 
eingebundener Libraries nicht hat, gibt es skurrile Fehlermeldungen. 
Verwendet man Konstanten oder wie hier eine Funktion, passiert das 
nicht. Außerdem haben Konstanten/Funktionen immer einen Typ; eine 
Konstante die ein "int" zurückgibt kann nie versehentlich einem "char*" 
zugewiesen werden. Ein Makro mit dem Wert 0 schon. Bei 
Funktionsoverloads oder Templates denen eine Konstante übergeben wird 
ist der Typ immer klar; bei Makros passiert es leicht dass der falsche 
verwendet wird.

In diesem Kontext hier hat die constexpr-Funktion noch einen anderen 
Vorteil: Man kann damit (rekursiv) Algorithmen schreiben, die vom 
Compiler berechnet werden, um die tatsächliche Zahl zu berechnen. Mit 
Makros geht das nicht.

Da C++ im Gegensatz zu C richtige Konstanten hat, kann man hier zur 
Definition von Zahlen komplett auf Makros verzichten und sollte es aus 
o.g. Gründen auch.
In C sind die meisten Compiler (wie GCC) auch schlau genug "static 
const" Variablen wegzuoptimieren, wenn man sie zur Definition von 
Konstanten verwendet, und daher kann (und sollte) sie hier auch 
verwenden.

von Daniel A. (daniel-a)


Lesenswert?

Dr. Sommer schrieb:
> Man kann damit (rekursiv) Algorithmen schreiben, die vom Compiler
> berechnet werden, um die tatsächliche Zahl zu berechnen.

Ein ergänzender Hinweis: constexpr funktionen müssen nur dann zur 
compiletime berechnet werden, wenn dessen Rückgabewert einer constexpr 
variable zugewiesen, oder als Constant Expression verwendet wird.

PS: Kennt jemand eine Anleitung wie man gcc 5.0 auf kubuntu installiert? 
Ich will c++14 features ausprobieren.

von Rolf M. (rmagnus)


Lesenswert?

Daniel A. schrieb:
> PS: Kennt jemand eine Anleitung wie man gcc 5.0 auf kubuntu installiert?
> Ich will c++14 features ausprobieren.

gcc 5.0 ist noch nicht fertig. Die aktuellste Version ist 4.9.2.
Wenn du 5.0 willst, wirst du es vermutlich selber bauen müssen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.