CodeNebula
C++17stladvanced

std::any

C++17 · Practical Modern · Compiler flag: -std=c++17

Explanation

A type-safe container for single values of any type. It uses type erasure internally and provides `std::any_cast` for safe retrieval, replacing `void*` patterns with a much safer alternative.

Real-World Scenario

Store heterogeneous configuration values (ints, strings, booleans) in a dynamic settings registry.

Quick Snippet

snippet.cpp
#include <any>
#include <string>

std::any config = 42;
int port = std::any_cast<int>(config);

config = std::string("localhost");
std::string host = std::any_cast<std::string>(config);

Full Example

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

// Demonstrates std::any, a type-erased container that can hold a value of any
// copy-constructible type. Unlike std::variant, the set of types is not fixed
// at compile time. Use std::any_cast to retrieve the stored value.

#include <iostream>
#include <any>
#include <string>
#include <vector>
#include <typeinfo>

// ------------------------------------------------------------------
// Helper: print the contents of an any object
// ------------------------------------------------------------------
void describe(const std::any& a) {
    if (!a.has_value()) {
        std::cout << "  (empty)" << std::endl;
        return;
    }
    std::cout << "  type: " << a.type().name();

    // Try common types
    if (a.type() == typeid(int)) {
        std::cout << ", value: " << std::any_cast<int>(a);
    } else if (a.type() == typeid(double)) {
        std::cout << ", value: " << std::any_cast<double>(a);
    } else if (a.type() == typeid(std::string)) {
        std::cout << ", value: " << std::any_cast<std::string>(a);
    } else if (a.type() == typeid(bool)) {
        std::cout << ", value: " << std::boolalpha << std::any_cast<bool>(a);
    } else {
        std::cout << ", value: (unknown type)";
    }
    std::cout << std::endl;
}

int main()
{
    // ------------------------------------------------------------------
    // 1. Basic construction
    // ------------------------------------------------------------------
    std::cout << "=== construction ===" << std::endl;
    std::any a1;                         // empty
    std::any a2 = 42;                    // int
    std::any a3 = 3.14;                  // double
    std::any a4 = std::string("hello");  // std::string

    describe(a1);
    describe(a2);
    describe(a3);
    describe(a4);

    // ------------------------------------------------------------------
    // 2. std::any_cast: safe value extraction
    // ------------------------------------------------------------------
    std::cout << "\n=== any_cast ===" << std::endl;
    int val = std::any_cast<int>(a2);
    std::cout << "  any_cast<int>(a2) = " << val << std::endl;

    // Bad cast throws std::bad_any_cast
    try {
        double bad = std::any_cast<double>(a2);  // a2 holds int, not double
        std::cout << "  (unexpected) " << bad << std::endl;
    } catch (const std::bad_any_cast& e) {
        std::cout << "  bad_any_cast: " << e.what() << std::endl;
    }

    // ------------------------------------------------------------------
    // 3. any_cast with pointer (returns nullptr on mismatch, no throw)
    // ------------------------------------------------------------------
    std::cout << "\n=== any_cast pointer ===" << std::endl;
    if (auto* p = std::any_cast<int>(&a2)) {
        std::cout << "  a2 is int: " << *p << std::endl;
    }
    if (auto* p = std::any_cast<double>(&a2)) {
        std::cout << "  a2 is double: " << *p << std::endl;
    } else {
        std::cout << "  a2 is NOT double (pointer is null)" << std::endl;
    }

    // ------------------------------------------------------------------
    // 4. Reassignment to a different type
    // ------------------------------------------------------------------
    std::cout << "\n=== type change ===" << std::endl;
    std::any flexible = 100;
    std::cout << "  before: "; describe(flexible);
    flexible = std::string("now a string");
    std::cout << "  after:  "; describe(flexible);
    flexible = true;
    std::cout << "  again:  "; describe(flexible);

    // ------------------------------------------------------------------
    // 5. reset and has_value
    // ------------------------------------------------------------------
    std::cout << "\n=== reset ===" << std::endl;
    std::any obj = 42;
    std::cout << "  has_value: " << std::boolalpha << obj.has_value() << std::endl;
    obj.reset();
    std::cout << "  after reset: " << obj.has_value() << std::endl;

    // ------------------------------------------------------------------
    // 6. emplace: construct in-place
    // ------------------------------------------------------------------
    std::cout << "\n=== emplace ===" << std::endl;
    std::any em;
    em.emplace<std::string>(5, '!');  // constructs string "!!!!!"
    std::cout << "  emplace<string>(5, '!'): "
              << std::any_cast<std::string>(em) << std::endl;

    // ------------------------------------------------------------------
    // 7. Heterogeneous container
    // ------------------------------------------------------------------
    std::cout << "\n=== heterogeneous vector ===" << std::endl;
    std::vector<std::any> items = {42, 3.14, std::string("mixed"), true};
    for (const auto& item : items) {
        describe(item);
    }

    return 0;
}

/*
Expected output:

=== construction ===
  (empty)
  type: i, value: 42
  type: d, value: 3.14
  type: ..., value: hello

=== any_cast ===
  any_cast<int>(a2) = 42
  bad_any_cast: bad any_cast

=== any_cast pointer ===
  a2 is int: 42
  a2 is NOT double (pointer is null)

=== type change ===
  before:   type: i, value: 100
  after:    type: ..., value: now a string
  again:    type: b, value: true

=== reset ===
  has_value: true
  after reset: false

=== emplace ===
  emplace<string>(5, '!'): !!!!!

=== heterogeneous vector ===
  type: i, value: 42
  type: d, value: 3.14
  type: ..., value: mixed
  type: b, value: true
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example any.cpp