C++ how to use std::any_cast and avoid else if statements I have created a Node class that I am using for various projects in my data structures class(at school) and I am overloading the insertion operator &lt;&lt;. I am using std::any for my container datatype inside Node class and am using std::any_cast to insert this data into a stream whenever possible. Std::any_cast requires that I know the datatype beforehand, and so I've come up with a hacky way to get this information by detangling the value typename into a string and then using a ton of else if statements to compare this string, as you can see in my code below... I'm looking for a different solution or even some advice about why this approach is fundamentally wrong and how to go about making better programming decisions. Lay it on me, I need help and can take it!

friend std::ostream&amp; operator &lt;&lt; (std::ostream&amp; out, Node&amp; n){

    std::string t;
    t = abi::__cxa_demangle(n.value.type().name(), 0, 0, 0);;

    if (t.find("string") != std::string::npos) { out &lt;&lt; std::any_cast&lt;std::string&gt;(n.value); }
    else if (t == "unsigned long long int") { out &lt;&lt; std::any_cast&lt;unsigned long long int&gt;(n.value); }
    else if (t == "unsigned long int") { out &lt;&lt; std::any_cast&lt;unsigned long int&gt;(n.value); }
    else if (t == "long long int") { out &lt;&lt; std::any_cast&lt;long long int&gt;(n.value); }
    else if (t == "long int") { out &lt;&lt; std::any_cast&lt;long int&gt;(n.value); }
    else if (t == "unsigned short int") { out &lt;&lt; std::any_cast&lt;unsigned short int&gt;(n.value); }
    else if (t == "short int"){ out &lt;&lt; std::any_cast&lt;short int&gt;(n.value); }
    else if (t == "int") { out &lt;&lt; std::any_cast&lt;int&gt;(n.value); }
    else if (t == "long double") { out &lt;&lt; std::any_cast&lt;long double&gt;(n.value); }
    else if (t == "double") { out &lt;&lt; std::any_cast&lt;double&gt;(n.value); }
    else if (t == "float") { out &lt;&lt; std::any_cast&lt;float&gt;(n.value); }
    else if (t == "bool") { out &lt;&lt; std::any_cast&lt;bool&gt;(n.value); }
    else if (t == "unsigned char") { out &lt;&lt; std::any_cast&lt;unsigned char&gt;(n.value); }
    else if (t == "signed char") { out &lt;&lt; std::any_cast&lt;signed char&gt;(n.value); }
    else if (t == "char") { out &lt;&lt; std::any_cast&lt;char&gt;(n.value); }
    else { out &lt;&lt; t; };

    return out;
};
First, this call to __cxa_demangle returns a buffer allocated with malloc and which must be freed. This isn't freed, so this code has a memory leak.

Second, as I understand it, __cxa_demangle does not exist in MSVC, so this is not portable.

Third, the .find("string") catches more than std::string. It would match std::wstring, std::stringstream, void (*)(std::string).

Fourth, this code relies essentially on knowing the potential types that are in that std::any. That is knowledge at a distance, and if you allow more types at the place of construction, you need more types here.

Fifth, if the type isn't one of those types, the error is silent and the output is the type contained, not the value. That could be harmless, but it could be a real problem. If you allowed type Foo in the any, and neglected to update this location, you wouldn't be able to tell if the output Foo was that type name or the value of a string stored in the any.

The suggestion of the other answer is to constrain the types stored using the type storing them. Instead of any use std::variant&lt;std::string, long long, unsigned long long, double&gt;. I added the string and unsigned options relative to the other answer. Then just visit:

std::visit([&amp;](const auto&amp; value) { out &lt;&lt; value; }, n.value);


This is a very strong option.

A second option would be to erase not almost every aspect of the type (as with std::any) but instead leave the interface you need, e.g. erase everything but the stream operator if that's all you need:

    printable p = 2.3;
    std::cout &lt;&lt; p &lt;&lt; "\n";
    p = "foo";
    std::cout &lt;&lt; p &lt;&lt; "\n";


Example: https://godbolt.org/z/NtJqWk

(edit: added a missing virtual destructor to impl_base)