ProgrammatieC++ ontwikkelaar

Wat zijn const-expressies (constexpr) in C++? In welke gevallen en waarom worden ze gebruikt, en wat is het verschil met macro's en const?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

Achtergrond

C++ ondersteunde oorspronkelijk alleen macro's (#define) en constanten (const). Echter, voor het definiëren van waarden tijdens de compilatie was dit niet voldoende. In C++11 is het sleutelwoord constexpr geïntroduceerd, wat het mogelijk maakt om waarden al in de compileertijd te berekenen, en niet alleen tijdens de uitvoering van het programma.

Probleem

Voordat constexpr bestond, moesten veel problemen worden opgelost met macro's (een ruwe tekstuele vervanger zonder typeveiligheid) of met const, welke niet altijd garandeerde dat een expressie in de compileertijd werd uitgevoerd. Dit bemoeilijkte de optimalisatie van het programma en leidde tot minder voorspelbaar gedrag.

Oplossing

constexpr garandeert de compiler dat de gedeclareerde expressie noodzakelijkerwijs in de compileertijd berekend zal worden, indien mogelijk. Dit wordt gebruikt voor het declareren van functies, variabelen en zelfs constructeurs en methoden van klassen die veilig en efficiënt in de compileertijd berekend kunnen worden.

Voorbeeld code:

constexpr int Square(int x) { return x * x; } constexpr int size = Square(5); // size wordt berekend in de compileertijd const int arr[size] = {}; // kan gebruikt worden als grootte van de array

Belangrijke kenmerken:

  • Garandeert berekening in de compileertijd (indien mogelijk).
  • Maakt het mogelijk om niet alleen variabelen, maar ook functies, methoden en constructeurs te declareren.
  • Verbetert de prestaties door vroege berekeningen en typeveiligheid.

Vragen met een valstrik.

Kan elke functie als constexpr worden gebruikt?

Nee. Een functie moet voldoen aan een aantal beperkingen: deze moet eenvoudig genoeg zijn, één return-statement bevatten (tot C++14) of enkel constant-berekenbare code omvatten (vanaf C++14 en hoger).

constexpr int f(int x) { return x + 2; } // ok constexpr int g(int x) { int y = x + 2; return y; } // tot C++14: compileert niet! daarna — mogelijk

Kunnen alle constexpr variabelen tijdens de compileertijd worden berekend?

Nee. Als bij de initiatie een niet-constant waarde wordt gebruikt of als een expressie niet berekend kan worden tijdens de compileertijd, zal er een fout optreden.

int val; // constexpr int x = f(val); // Fout: val is niet geïnitialiseerd!

Wat is het verschil tussen constexpr en const?

const garandeert alleen dat de waarde niet kan worden gewijzigd, maar garandeert niet dat deze in de compileertijd wordt berekend. constexpr vereist dat de waarde tijdens de compileertijd wordt berekend (indien mogelijk).

const int x = time(nullptr); // ok, maar wordt in de uitvoering berekend constexpr int y = 42; // ok, wordt in de compileertijd berekend

Typische fouten en antipatterns

  • Verwarring tussen const en constexpr
  • Pogingen om complexe logische constructies te gebruiken in constexpr-functies voor C++14
  • Onjuist gebruik van niet-const variabelen in de constexpr-context

Voorbeeld uit het leven

Negatieve case

Een ontwikkelaar gebruikt #define PI 3.14 voor alle berekeningen van de oppervlakte van een cirkel.

Voordelen:

  • Eenvoudig te schrijven

Nadelen:

  • Geen typeveiligheid, mogelijke vervangfout
  • Kan niet worden gebruikt als constexpr in sjablonen of array-parameters

Positieve case

Een ontwikkelaar gebruikt constexpr double PI = 3.141592653589793; en sjabloon constexpr-functies voor berekeningen.

Voordelen:

  • Typeveiligheid
  • Optimalisatie tijdens de compilatie
  • Veelzijdigheid van gebruik (bijvoorbeeld in templates).

Nadelen:

  • Iets hogere vereisten voor het begrijpen van de code; ondersteuning voor C++11+ vereist