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.
#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;
}
This example demonstrates the basic usage of static_assert
:
process_integral
that is intended to work only with integral types.static_assert
to ensure that the type T
is indeed an integral type.std::is_integral
type trait to check if T
is integral.main()
, calling the function with an integer (42) works fine.#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;
}
This example showcases how static_assert
can be used with compile-time calculations:
constexpr
function fibonacci
that calculates Fibonacci numbers.main()
, we calculate the 10th Fibonacci number at compile-time.static_assert
to verify that the result is correct (55 for the 10th Fibonacci number).static_assert
can be used to validate compile-time computations.#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;
}
This example demonstrates using static_assert
to enforce type relationships:
check_inheritance
that uses static_assert
to ensure that Derived
inherits from Base
.std::is_base_of
type trait to check the inheritance relationship.main()
, we successfully verify the inheritance relationship between Animal
and Dog
, and Animal
and Cat
.Animal
and Plant
would result in a compile-time error.#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;
}
This example illustrates using static_assert
to enforce constraints on template parameters:
FixedBuffer
class template with two template parameters: T
(type) and Size
.static_assert
ensures that the buffer size is greater than zero.static_assert
uses std::is_trivially_copyable
to ensure that T
is a type that can be safely copied byte-by-byte.main()
, we create and use valid instances of FixedBuffer
.FixedBuffer
with size 0 would result in a compile-time error.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:
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.