static_assert


Introduction

static_assert is a powerful feature in C++ that allows developers to perform compile-time assertions. Introduced in C++11, it enables early detection of errors and helps enforce certain conditions at compile-time rather than runtime. This can lead to more robust code and can catch potential issues before they become runtime problems.

Example 1: Basic Usage

#include <iostream>
#include <type_traits>

template <typename T>
void process_integral(T value) {
    static_assert(std::is_integral<T>::value, "T must be an integral type");
    std::cout << "Processing integral value: " << value << std::endl;
}

int main() {
    process_integral(42);
    // Uncommenting the next line would result in a compile-time error
    // process_integral(3.14);
    return 0;
}

Explanation

This example demonstrates the basic usage of static_assert:

Example 2: Compile-Time Calculations

#include <iostream>

constexpr int fibonacci(int n) {
    return (n <= 1) ? n : fibonacci(n-1) + fibonacci(n-2);
}

int main() {
    constexpr int result = fibonacci(10);
    static_assert(result == 55, "Fibonacci calculation is incorrect");

    std::cout << "The 10th Fibonacci number is: " << result << std::endl;
    return 0;
}

Explanation

This example showcases how static_assert can be used with compile-time calculations:

Example 3: Enforcing Type Relationships

#include <iostream>
#include <type_traits>

template <typename Base, typename Derived>
void check_inheritance() {
    static_assert(std::is_base_of<Base, Derived>::value, 
                  "Derived must inherit from Base");
    std::cout << "Inheritance relationship verified." << std::endl;
}

class Animal {};
class Dog : public Animal {};
class Cat : public Animal {};
class Plant {};

int main() {
    check_inheritance<Animal, Dog>();
    check_inheritance<Animal, Cat>();
    // Uncommenting the next line would result in a compile-time error
    // check_inheritance<Animal, Plant>();
    return 0;
}

Explanation

This example demonstrates using static_assert to enforce type relationships:

Example 4: Enforcing Constraints on Template Parameters

#include <iostream>
#include <type_traits>

template <typename T, size_t Size>
class FixedBuffer {
    static_assert(Size > 0, "Buffer size must be greater than zero");
    static_assert(std::is_trivially_copyable<T>::value, 
                  "T must be trivially copyable for FixedBuffer");

    T buffer[Size];

public:
    void fill(const T& value) {
        for (size_t i = 0; i < Size; ++i) {
            buffer[i] = value;
        }
    }

    void print() const {
        for (size_t i = 0; i < Size; ++i) {
            std::cout << buffer[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    FixedBuffer<int, 5> intBuffer;
    intBuffer.fill(42);
    intBuffer.print();

    FixedBuffer<double, 3> doubleBuffer;
    doubleBuffer.fill(3.14);
    doubleBuffer.print();

    // Uncommenting the next line would result in a compile-time error
    // FixedBuffer<int, 0> zeroSizeBuffer;

    return 0;
}

Explanation

This example illustrates using static_assert to enforce constraints on template parameters:

Summary

static_assert is a valuable tool in modern C++ for enforcing compile-time constraints and catching potential errors early in the development process. It can be used to:

  1. Validate type properties in template functions and classes.
  2. Verify compile-time calculations.
  3. Enforce type relationships and inheritance hierarchies.
  4. Set constraints on template parameters.

By leveraging static_assert, developers can create more robust and self-documenting code, catching many issues at compile-time rather than runtime. This leads to improved code quality, better performance (by avoiding runtime checks), and clearer expression of design intent in the code.

Related

Previous Page | Course Schedule | Course Content