std::any_cast(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

okay bestie, welcome to the std::any_cast(3) page from the C++ Standard Libary manual πŸ’– this one is all about type-safe access to whatever is hiding inside a std::any, and it’s lowkey iconic.

🌸 NAME 🌸

std::any_cast β€” std::any_cast (yes, the name is literally the same thing twice, periodt πŸ’…)

✨ Synopsis ✨

Defined in header <any>.

Here are the five overloads, all (since C++17):

template< class T >                               (1) (since C++17)
T any_cast( const any& operand );
template< class T >                               (2) (since C++17)
T any_cast( any& operand );
template< class T >                               (3) (since C++17)
T any_cast( any&& operand );
template< class T >                               (4) (since C++17)
const T* any_cast( const any* operand ) noexcept;
template< class T >                               (5) (since C++17)
T* any_cast( any* operand ) noexcept;

This whole thing performs type-safe access to the contained object. Let U be std::remove_cv_t<std::remove_reference_t<T>> β€” write that down, bestie, it matters.

  • 1) the program is ill-formed if std::is_constructible_v<T, const U&> is false.
  • 2) the program is ill-formed if std::is_constructible_v<T, U&> is false.
  • 3) the program is ill-formed if std::is_constructible_v<T, U> is false.
  • 4, 5) the program is ill-formed if std::is_void_v<T> is true.

No cap, these constraints are the vibe check for whether the overload even exists.

πŸŽ€ Parameters πŸŽ€

  • operand β€” the target any object. That’s the little container we’re trying to peek inside 🫢

πŸ’– Return value πŸ’–

  • 1, 2) Returns static_cast<T>(*std::any_cast<U>(&operand)).
  • 3) Returns static_cast<T>(std::move(*std::any_cast<U>(&operand))).
  • 4, 5) If operand is not a null pointer, and the typeid of the requested T matches that of the contents of operand, you get a pointer to the value contained by operand; otherwise you get a null pointer. So yeah, the pointer overloads are doing a lil find-my-type mission πŸ”₯

🚨 Exceptions 🚨

  • 1–3) Throws std::bad_any_cast if the typeid of the requested T does not match that of the contents of operand. So if you guessed wrong, it’s gonna yell at you 😭

🧚 Example 🧚

        #include <any>
        #include <iostream>
        #include <string>
        #include <type_traits>
        #include <utility>

        int main()
        {
            // Simple example
            auto a1 = std::any(12);
            std::cout << "1) a1 is int: " << std::any_cast<int>(a1) << '\n';

            try
            {
                auto s = std::any_cast<std::string>(a1); // throws
            }
            catch (const std::bad_any_cast& e)
            {
                std::cout << "2) " << e.what() << '\n';
            }

            // Pointer example
            if (int* i = std::any_cast<int>(&a1))
                std::cout << "3) a1 is int: " << *i << '\n';
            else if (std::string* s = std::any_cast<std::string>(&a1))
                std::cout << "3) a1 is std::string: " << *s << '\n';
            else
                std::cout << "3) a1 is another type or unset\n";

            // Advanced example
            a1 = std::string("hello");
            auto& ra = std::any_cast<std::string&>(a1); //< reference
            ra[1] = 'o';

            std::cout << "4) a1 is string: "
                      << std::any_cast<std::string const&>(a1) << '\n'; //<
       const reference

            auto s1 = std::any_cast<std::string&&>(std::move(a1)); //< rvalue
       reference
            // Note: β€œs1” is a move-constructed std::string:
            static_assert(std::is_same_v<decltype(s1), std::string>);

            // Note: the std::string in β€œa1” is left in valid but unspecified
       state
            std::cout << "5) a1.size(): "
                      << std::any_cast<std::string>(&a1)->size() //< pointer
                      << '\n'
                      << "6) s1: " << s1 << '\n';
        }

🌈 Possible output 🌈

1) a1 is int: 12
2) bad any_cast
3) a1 is int: 12
4) a1 is string: hollo
5) a1.size(): 0
6) s1: hollo

Bestie, notice hollo β€” that’s not a typo in the output, the example literally changes ra[1] = 'o' so hello becomes hollo πŸ’€ iconic behavior.

🩹 Defect reports 🩹

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

  • DR: LWG 3305
    • Applied to: C++17
    • Behavior as published: the behavior of overloads (4,5) was unclear if T is void.
    • Correct behavior: the program ill-formed in this case.

mwah πŸ’‹ this page came from http://cppreference.com, version 2024.06.10, and it’s the std::any_cast(3) page β€” go forth and type-safe-access the heck out of your std::any, bestie πŸ’–βœ¨

πŸ“¦ where this page comes from