'Cant cout item in container with std::any

This script

#include <iostream>
#include <unordered_map>
#include <any>
using namespace std;

int main() {
    unordered_map<int, any> test;
    test[5] = "Hey!";
    cout << test[5];
    return 0;
}

Why does it not work?

candidate function not viable: no known conversion from 'std::__ndk1::unordered_map<int, std::__ndk1::any, std::__ndk1::hash<int>, std::__ndk1::equal_to<int>, std::__ndk1::allocator<std::__ndk1::pair<const int, std::__ndk1::any> > >::mapped_type' (aka 'std::__ndk1::any') to 'const void *' for 1st argument; take the address of the argument with &
    basic_ostream& operator<<(const void* __p);

Sorry if this sounds a little stupid



Solution 1:[1]

Just add a any_cast to test[5]. The main reason for this cast, is to tell the compiler which overloaded function of << is to be called for test[5], << doesn't have any function defined for std::any. Hence, we told the compiler to call const char * or std::string overload function of <<.

Always, make sure that sizeof of allocation of test[n] must match the sizeof type-cast. For an example:

sizeof(std::string) = 32 bytes

sizeof(const char *) = 8 bytes

That's why we first need to allocate test[5] using std::string("Hey!");, instead of just "Hey!".

But, sizeof(int *) is equal to sizeof(char *), if you did this, it can cause 3 problems:

  1. segfault
  2. undefined behavior
  3. Exception: std::bad_any_cast

Fix

std::cout << std::any_cast<const char *>(test[5]);

or std::string

test[5] = std::string("Hey!");
std::cout << std::any_cast<std::string>(test[5]);

Solution 2:[2]

This is because there is no defined overload for the << operator for a std::ostream and std::any.

<< is defined for string literals, std::strings, numbers, and a few other specific objects. std::any is none of those.

Just because it happens to actually contain a string doesn't make it into a std::string or anything else. Just because you open the door to your car, go inside and sit down, or put your dog into the car, or a bunch of groceries, doesn't turn your car into a human, or dog, or a bunch of vegetables. It's still a car, just with something inside it.

So there is no << operator defined for this. That's what your C++ compiler is telling you: it needs the << operator defined for std::ostream and std::any and there isn't one.

Solution 3:[3]

To solve the error you can use std::any_cast which gives type-safe access to the contained object, as shown below:

std::cout <<  std::any_cast<const char*>(test[5]);

Or

test[5] = std::string("Hey!");    
std::cout <<  std::any_cast<std::string>(test[5]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Sam Varshavchik
Solution 3 Darth-CodeX