CodeNebula
C++14stlintermediate

std::is_final

C++14 · Modern Refined · Compiler flag: -std=c++14

Explanation

A compile-time type trait that evaluates to `true` if a class is declared `final` (cannot be inherited from). This is useful in template metaprogramming to select optimized implementations — for example, using the Empty Base Optimization (EBO) only when a type is not final.

Real-World Scenario

A generic compressed-pair implementation (like the one inside many standard library `unique_ptr` implementations) checks `std::is_final` to decide whether it can inherit from the deleter type to exploit EBO, or must store it as a member instead.

Quick Snippet

snippet.cpp
#include <type_traits>
#include <iostream>

class Base {};
class Derived final : public Base {};

template<typename T>
void describe() {
    if constexpr (std::is_final<T>::value)
        std::cout << "Type is final — cannot derive from it\n";
    else
        std::cout << "Type is not final — inheritance allowed\n";
}

int main() {
    describe<Base>();    // not final
    describe<Derived>(); // final
}

Full Example

is_final.cpp
// CodeNebula - C++14 Example: std::is_final
// Compile: g++ -std=c++14 -Wall -Wextra -o example is_final.cpp

// Demonstrates the std::is_final type trait added in C++14. It checks at
// compile time whether a class is declared 'final' (cannot be inherited from).
// Real-world use: template metaprogramming to choose between inheritance-based
// and composition-based strategies, static assertions in framework code,
// and optimizations like Empty Base Optimization (EBO) decisions.

#include <iostream>
#include <type_traits>
#include <string>

// ------------------------------------------------------------------
// 1. Regular class (not final)
// ------------------------------------------------------------------
class Animal
{
public:
    virtual ~Animal() = default;
    virtual std::string speak() const { return "..."; }
};

// ------------------------------------------------------------------
// 2. Final class (cannot be inherited)
// ------------------------------------------------------------------
class Dog final : public Animal
{
public:
    std::string speak() const override { return "Woof!"; }
};

// ------------------------------------------------------------------
// 3. Final class with no base
// ------------------------------------------------------------------
class Singleton final
{
    int value_;
public:
    explicit Singleton(int v) : value_(v) {}
    int value() const { return value_; }
};

// ------------------------------------------------------------------
// 4. Non-final class
// ------------------------------------------------------------------
class Widget
{
    int id_;
public:
    explicit Widget(int id) : id_(id) {}
    int id() const { return id_; }
};

// ------------------------------------------------------------------
// 5. Template that adapts behavior based on is_final
// ------------------------------------------------------------------
template<typename T, bool IsFinal = std::is_final<T>::value>
struct Wrapper;

// Specialization for non-final: can inherit (enables EBO)
template<typename T>
struct Wrapper<T, false> : private T
{
    int extra_data;
    Wrapper(T base, int data) : T(std::move(base)), extra_data(data) {}
    static const char* strategy() { return "inheritance (EBO eligible)"; }
    const T& base() const { return static_cast<const T&>(*this); }
};

// Specialization for final: must compose (cannot inherit)
template<typename T>
struct Wrapper<T, true>
{
    T base_obj;
    int extra_data;
    Wrapper(T base, int data) : base_obj(std::move(base)), extra_data(data) {}
    static const char* strategy() { return "composition (final class)"; }
    const T& base() const { return base_obj; }
};

int main()
{
    // ------------------------------------------------------------------
    // 1. Basic is_final checks
    // ------------------------------------------------------------------
    std::cout << "=== std::is_final Checks ===" << std::endl;
    std::cout << std::boolalpha;
    std::cout << "  is_final<Animal>    : " << std::is_final<Animal>::value << std::endl;
    std::cout << "  is_final<Dog>       : " << std::is_final<Dog>::value << std::endl;
    std::cout << "  is_final<Singleton> : " << std::is_final<Singleton>::value << std::endl;
    std::cout << "  is_final<Widget>    : " << std::is_final<Widget>::value << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. With fundamental and standard library types
    // ------------------------------------------------------------------
    std::cout << "=== Standard Types ===" << std::endl;
    std::cout << "  is_final<int>       : " << std::is_final<int>::value << std::endl;
    std::cout << "  is_final<std::string>: " << std::is_final<std::string>::value << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. Adaptive wrapper using is_final
    // ------------------------------------------------------------------
    std::cout << "=== Adaptive Wrapper Pattern ===" << std::endl;

    Wrapper<Widget> w1(Widget(42), 100);
    std::cout << "  Wrapper<Widget>   : " << w1.strategy()
              << ", id=" << w1.base().id() << std::endl;

    Wrapper<Singleton> w2(Singleton(7), 200);
    std::cout << "  Wrapper<Singleton>: " << w2.strategy()
              << ", value=" << w2.base().value() << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. Size comparison showing EBO effect
    // ------------------------------------------------------------------
    std::cout << "=== Size Comparison (EBO Effect) ===" << std::endl;
    std::cout << "  sizeof(Widget)           : " << sizeof(Widget) << std::endl;
    std::cout << "  sizeof(Wrapper<Widget>)  : " << sizeof(Wrapper<Widget>) << std::endl;
    std::cout << "  sizeof(Singleton)        : " << sizeof(Singleton) << std::endl;
    std::cout << "  sizeof(Wrapper<Singleton>): " << sizeof(Wrapper<Singleton>) << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 5. Static assert example (compile-time enforcement)
    // ------------------------------------------------------------------
    std::cout << "=== Compile-Time Enforcement ===" << std::endl;
    static_assert(std::is_final<Dog>::value,
                  "Dog must be final for security reasons");
    static_assert(!std::is_final<Animal>::value,
                  "Animal must not be final to allow polymorphism");
    std::cout << "  static_assert(is_final<Dog>)     : passed" << std::endl;
    std::cout << "  static_assert(!is_final<Animal>) : passed" << std::endl;

    return 0;
}

/*
Expected output:

=== std::is_final Checks ===
  is_final<Animal>    : false
  is_final<Dog>       : true
  is_final<Singleton> : true
  is_final<Widget>    : false

=== Standard Types ===
  is_final<int>       : false
  is_final<std::string>: false

=== Adaptive Wrapper Pattern ===
  Wrapper<Widget>   : inheritance (EBO eligible), id=42
  Wrapper<Singleton>: composition (final class), value=7

=== Size Comparison (EBO Effect) ===
  sizeof(Widget)           : 4
  sizeof(Wrapper<Widget>)  : 8
  sizeof(Singleton)        : 4
  sizeof(Wrapper<Singleton>): 8

=== Compile-Time Enforcement ===
  static_assert(is_final<Dog>)     : passed
  static_assert(!is_final<Animal>) : passed
*/
Run command
g++ -std=c++14 -Wall -Wextra -o example is_final.cpp