C++ constexpr Function | 'Compile-Time Function' Guide
이 글의 핵심
constexpr int square(int x) { return x * x; }.
What is constexpr Function?
Function usable at both compile-time and runtime
Below is an implementation example using C++. Understand the role of each part while examining the code.
constexpr int square(int x) {
return x * x;
}
int main() {
// Compile-time
constexpr int a = square(5); // 25 (calculated at compile time)
// Runtime
int x = 10;
int b = square(x); // Runtime calculation
}
C++11 vs C++14 vs C++17
Here is detailed implementation code using C++. Process data with loops and perform branching with conditionals. Understand the role of each part while examining the code.
// C++11: Single return statement only
constexpr int factorial11(int n) {
return n <= 1 ? 1 : n * factorial11(n - 1);
}
// C++14: Like regular functions
constexpr int factorial14(int n) {
int result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
// C++17: if constexpr added
template<typename T>
constexpr auto process(T value) {
if constexpr (std::is_integral_v<T>) {
return value * 2;
} else {
return value;
}
}
Basic Usage
Below is an implementation example using C++. Understand the role of each part while examining the code.
// Simple calculation
constexpr int add(int a, int b) {
return a + b;
}
constexpr int multiply(int a, int b) {
return a * b;
}
// Use as array size
constexpr int SIZE = add(10, 20);
int arr[SIZE]; // Compile-time size
Practical Examples
Example 1: Math Functions
Here is detailed implementation code using C++. Process data with loops and perform branching with conditionals. Understand the role of each part while examining the code.
constexpr int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
constexpr int power(int base, int exp) {
int result = 1;
for (int i = 0; i < exp; i++) {
result *= base;
}
return result;
}
constexpr bool isPrime(int n) {
if (n <= 1) return false;
if (n == 2) return true;
if (n % 2 == 0) return false;
for (int i = 3; i * i <= n; i += 2) {
if (n % i == 0) return false;
}
return true;
}
int main() {
constexpr int fib10 = fibonacci(10); // 55 (compile-time)
constexpr int pow = power(2, 10); // 1024
constexpr bool prime = isPrime(17); // true
std::cout << fib10 << std::endl;
std::cout << pow << std::endl;
std::cout << prime << std::endl;
}
Example 2: String Processing
Here is detailed implementation code using C++. Process data with loops and perform branching with conditionals. Understand the role of each part while examining the code.
constexpr size_t strlen_constexpr(const char* str) {
size_t len = 0;
while (str[len] != '\0') {
len++;
}
return len;
}
constexpr bool startsWith(const char* str, const char* prefix) {
while (*prefix != '\0') {
if (*str != *prefix) {
return false;
}
str++;
prefix++;
}
return true;
}
int main() {
constexpr size_t len = strlen_constexpr("Hello"); // 5
constexpr bool starts = startsWith("Hello World", "Hello"); // true
char buffer[len + 1]; // Compile-time size
}
Example 3: Hash Function
Here is detailed implementation code using C++. Process data with loops and perform branching with conditionals. Understand the role of each part while examining the code.
constexpr unsigned int hash(const char* str) {
unsigned int hash = 5381;
while (*str) {
hash = ((hash << 5) + hash) + *str;
str++;
}
return hash;
}
int main() {
// Compile-time hash
constexpr unsigned int h1 = hash("apple");
constexpr unsigned int h2 = hash("banana");
// Use in switch statement
const char* fruit = "apple";
switch (hash(fruit)) {
case hash("apple"):
std::cout << "Apple" << std::endl;
break;
case hash("banana"):
std::cout << "Banana" << std::endl;
break;
}
}
Example 4: Array Initialization
Here is detailed implementation code using C++. Process data with loops. Understand the role of each part while examining the code.
constexpr int generateValue(int index) {
return index * index;
}
template<size_t N>
constexpr std::array<int, N> generateArray() {
std::array<int, N> arr{};
for (size_t i = 0; i < N; i++) {
arr[i] = generateValue(i);
}
return arr;
}
int main() {
constexpr auto arr = generateArray<10>();
// arr = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
for (int x : arr) {
std::cout << x << " ";
}
}
constexpr Classes
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
class Point {
private:
int x, y;
public:
constexpr Point(int x, int y) : x(x), y(y) {}
constexpr int getX() const { return x; }
constexpr int getY() const { return y; }
constexpr int distanceSquared() const {
return x * x + y * y;
}
};
int main() {
constexpr Point p(3, 4);
constexpr int dist = p.distanceSquared(); // 25
int arr[dist]; // Compile-time size
}
Common Issues
Issue 1: Calling Non-constexpr Function
Here is detailed implementation code using C++. Understand the role of each part while examining the code.
int nonConstexpr(int x) {
return x * 2;
}
// ❌ Call non-constexpr function
constexpr int func(int x) {
return nonConstexpr(x); // Error
}
// ✅ Call only constexpr functions
constexpr int constexprFunc(int x) {
return x * 2;
}
constexpr int func(int x) {
return constexprFunc(x); // OK
}
Issue 2: Static Variables
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ❌ Static variable (C++11)
constexpr int func() {
static int count = 0; // Error
return count++;
}
// ✅ Allowed from C++14
constexpr int func14() {
static int count = 0; // OK (C++14)
return count++;
}
Issue 3: Virtual Functions
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
class Base {
public:
// ❌ constexpr virtual function (before C++17)
virtual constexpr int getValue() const {
return 42;
}
};
// ✅ C++20: constexpr virtual allowed
class Base20 {
public:
virtual constexpr int getValue() const {
return 42;
}
};
Summary
Key Points
- constexpr function: Usable at compile-time and runtime
- C++11: Single return statement only
- C++14: Loops and variables allowed
- C++17: if constexpr added
- C++20: Virtual functions allowed
When to Use
✅ Use constexpr when:
- Need compile-time constants
- Want to optimize performance
- Array size calculation
- Template metaprogramming
❌ Don’t use when:
- Function has side effects
- Calls non-constexpr functions
- Too complex (readability matters)
Best Practices
- ✅ Use constexpr for pure functions
- ✅ Combine with templates
- ✅ Use for compile-time optimization
- ❌ Don’t overuse (readability first)
- ❌ Don’t use for I/O operations
Related Articles
- C++ Compile-Time Programming
- C++ constexpr Lambda
- C++ if constexpr
Master compile-time programming with constexpr! 🚀