1

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

Bfyuvf
  • 139
  • 9
  • 4
    You need to `std::any_cast` it to a specific type – UnholySheep May 13 '22 at 10:01
  • 4
    You can't do anything with `std::any` directly, you need to use `std::any_cast` to extract the contained value – Alan Birtles May 13 '22 at 10:01
  • @AlanBirtles not strictly true. You can copy or move the `any`, or replace the value it contains – Caleth May 13 '22 at 10:05
  • You should get used to reading the documentation on a regular basis. [std::any](https://en.cppreference.com/w/cpp/utility/any) – digito_evo May 13 '22 at 10:05
  • `std::any` is cool, but it is needed quite rarely. Mixing it with `std::unordered_map` is strange. That is why I would recommend you to explain why you think your code needs `std::unordered_map`, I'm pretty sure there is better solution for your task your code should solve. – Marek R May 13 '22 at 10:14
  • A heterogeneous array of user inputs, using unordered_map – Bfyuvf May 13 '22 at 10:18
  • [`std::variant`](https://en.cppreference.com/w/cpp/utility/variant) might be more appropriate if allowed types are limited – Jarod42 May 13 '22 at 10:22
  • Ok, so any_cast works, but what if I don't even know what the type that the any is covering is? Making a catch() for every type is inefficient – Bfyuvf May 14 '22 at 07:38

3 Answers3

5

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.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
2

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]);
Darth-CodeX
  • 2,166
  • 1
  • 6
  • 23
Jason
  • 36,170
  • 5
  • 26
  • 60
2

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]);
Darth-CodeX
  • 2,166
  • 1
  • 6
  • 23