Constrained Non Type Template Parameter

NTTP (C++98): Allows templates to accept non-type parameters like integers or pointers, enhancing flexibility and efficiency. CNTTP (C++20): Extends NTTP by using concepts to constrain non-type parameters, improving type safety and expressiveness. Code Example #include <concepts> #include <cstddef> // Function using NTTP template<size_t i> // size_t is unsigned, so negative values will cause an error auto get_value_nttp() { return i; } // Function using CNTTP template<std::integral auto I> // constrained to integral types auto get_value_cnttp() { return I; } int main() { // NTTP example auto x = get_value_nttp<10>(); // correct, 10 is a valid size_t // auto y = get_value_nttp<-10>(); // error, -10 is not a valid size_t (uncomment to see the error) // CNTTP example auto w = get_value_cnttp<10>(); // correct, 10 is an integral type auto z = get_value_cnttp<-10>(); // correct, -10 is an integral type return 0; }

June 17, 2024 · 142 words · Me

Class Template Argument Deduction

Class Template Argument Deduction (CTAD) is a feature introduced in C++17 that allows the compiler to deduce the template arguments for class templates from the constructor arguments. This makes code more concise and avoids the need for explicit template arguments. Example without CTAD: #include <vector> #include <iostream> int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; // Explicit template argument for (const auto& elem : vec) { std::cout << elem << " "; } return 0; } Example with CTAD: #include <vector> #include <iostream> int main() { std::vector vec1 = {1, 2, 3, 4, 5}; // CTAD deduces std::vector<int> std::vector vec2 = {1....

May 7, 2024 · 142 words · Me

Non-Virtual Polymorphism

Modern Features in C++17 Non-virtual runtime polymorphism can be achieved with modern C++ (e.g., C++17) features std::any and std::variant as described in the table below. Notice std::tuple is not used for polymorphism; it offers a structured way to manage multiple values of different types simultaneously, such as in function return types, or parameter packs. It is put here because of its usage is a bit similar to std::any and std::variant....

January 24, 2024 · 768 words · Me

Observable Behaviors

What is Observable Behavior & Related Issues The term observable behavior, according to the standard, means the following: — Accesses (reads and writes) to volatile objects occur strictly according to the semantics of the expressions in which they occur. In particular, they are not reordered with respect to other volatile accesses on the same thread. — At program termination, all data written into files shall be identical to one of the possible results that execution of the program according to the abstract semantics would have produced....

December 2, 2023 · 804 words · Me

Trivial Class vs Aggregate Structure

Trivial Class vs Aggregate Structure Trivial Class A trivial class is a class that: Has a trivial default constructor. Has a trivial copy constructor. Has a trivial move constructor (since C++11). Has a trivial copy assignment operator. Has a trivial move assignment operator (since C++11). Has a trivial destructor. Has no virtual functions or virtual base classes. The trivial constructors/operations/destructor means they are not user-provided (i.e., is implicitly-defined or defaulted on its first declaration)....

November 1, 2023 · 258 words · Me

Initialization With Brackets

The table summarizes how brackets {} and () are related to list-initialization in various contexts. The column Allows Narrowing Conversion indicates whether implicit type conversions that lose information are allowed. The column Allows Explicit Constructors indicates whether the syntax can call constructors marked as explicit. The columns Use for Aggregates and Use for User-Defined Types show the applicability of each initialization type for aggregates like arrays (e.g., int x[3][4]) and structs, and user-defined types like classes, respectively....

October 29, 2023 · 142 words · Me

Scope Guard

Background Scope Guard is a concept reminiscent of the RAII (Resource Acquisition Is Initialization) principle in C++. The idea is to manage resources (like memory, files, network sockets, etc.) using object lifetime. When the object goes out of scope, its destructor ensures that the resource is cleaned up properly. The scope guard is intended to run a given callable (like a function or lambda) when it is destroyed. RAII (Resource Acquisition Is Initialization) is a programming idiom used in C++ where the lifetime of an object is bound to the lifetime of its scope (typically represented by a block of code wrapped in curly braces {})....

August 29, 2023 · 629 words · Me

Static Local Member

C++ templates are blueprints and don’t represent specific types until they are instantiated with actual types. Once instantiated, the compiler creates a specific version of that template for the provided type. For template classes, each instantiation has its own unique version of the static members, making them distinct for each type the template is instantiated with. ///////////////////// // Code Block 1 ///////////////////// #include<iostream> class ComponentBase{ protected: // component_type_count is a static variable shared by derived classes static inline size_t component_type_count = 0; }; template<typename T> class Component : public ComponentBase{ public: static size_t component_type_id(){ // ID is the static local variable for a particular type T static size_t ID = component_type_count++; return ID; } }; class A : public Component<A> {}; class B : public Component<B> {}; class C : public Component<C> {}; int main() { std::cout << A::component_type_id() << std::endl; // 0 std::cout << B::component_type_id() << std::endl; // 1 std::cout << B::component_type_id() << std::endl; // 1 std::cout << A::component_type_id() << std::endl; // 0 std::cout << A::component_type_id() << std::endl; // 0 std::cout << C::component_type_id() << std::endl; // 2 } Key Points:...

August 27, 2023 · 373 words · Me

Formatter Specialization

We can customize the (printing) format of a given class by using the specialization of formatter. #include <format> #include <iostream> struct Frac { int a, b; }; template <> struct std::formatter<Frac> : std::formatter<string_view> { // parse() is inherited from the base class std::formatter<string_view> // * an efficient solution: auto format(const Frac& frac, std::format_context& ctx) const { return std::format_to(ctx.out(), "{}/{}", frac.a, frac.b); } // the same functionality as above, but inefficient due to the temporary string // auto format(const Frac& frac, std::format_context& ctx) const { // std::string temp; // std::format_to(std::back_inserter(temp), "{}/{}", // frac....

August 25, 2023 · 154 words · Me

User Defined Literals

User Defined Literals (UDL) produces an object in an interesting way: constexpr auto operator""_f(const char* fmt, size_t) { return[=]<typename... T>(T&&... Args) { return std::vformat(fmt, std::make_format_args(std::forward<T>(Args)...)); }; } auto s = "example {} see {}"_f("yep", 1.1); // s = "example yep 1.1" The UDL _f has the same effect of std::format("example {} see {}", "yep", 1.1). Pretty familiar (as libfmt), right? Now, let’s break the definition of _f down: int x = 10; double y = 3....

August 22, 2023 · 330 words · Me