Trying to output a map object where the value can be any data type. Tried the following:
#include <iostream>
#include <unordered_map>
#include <any>
std::unordered_map<std::string, std::any> example = {
{"first", 'A'},
{"second", 2},
{"third", 'C'}
};
std::ostream &operator<<(std::ostream &os,
const std::any &m) {
for (auto &t : example) {
os << "{" << t.first << ": " << t.second << "}\n";
}
return os;
}
int main()
{std::cout << example;
return 0;
}
But,getting infinite loop of values.
CodePudding user response:
There isn't a good way of printing the contents of an arbitrary std::unordered_map<std::string, std::any>
. It might have contents that aren't printable, and you've discarded the information about what type the contents actually are. You need to keep that information somewhere.
#include <string>
#include <iostream>
#include <unordered_map>
#include <any>
#include <utility>
template <typename T>
std::ostream & print_any(std::ostream & os, const std::any & any) {
return os << std::any_cast<const std::decay_t<T> &>(any);
}
class any_printable {
using print_t = std::ostream & (*)(std::ostream &, const std::any &);
std::any value;
print_t print;
public:
template <typename T>
any_printable(T&& t) : value(std::forward<T>(t)), print(print_any<T>) {}
friend std::ostream & operator<<(std::ostream & os, const any_printable & ap) {
return ap.print(os, ap.value);
}
};
std::ostream &operator<<(std::ostream &os, const std::unordered_map<std::string, any_printable> &map) {
for (auto & [key, value] : map) {
os << "{" << key << ": " << value << "}\n";
}
return os;
}
int main() {
std::unordered_map<std::string, any_printable> example = {
{"first", 'A'},
{"second", 2},
{"third", 'C'}
};
std::cout << example;
}
CodePudding user response:
Another alternative is to register the printing functions corresponding to each type into the hash table and use type_index(any::type)
as the key to access the corresponding printing function at runtime.
#include <any>
#include <iostream>
#include <unordered_map>
#include <typeindex>
template<class... Ts>
auto gen_any_printer = std::unordered_map{
std::pair{
std::type_index(typeid(Ts)),
[](std::ostream& os, const std::any& a) -> auto&
{ return os << std::any_cast<Ts const&>(a); }
}...
};
std::ostream& operator<<(std::ostream& os, const std::any& a) {
const static auto any_printer = gen_any_printer<char, int, const char*>;
return any_printer.at(std::type_index(a.type()))(os, a);
}
std::ostream& operator<<(
std::ostream& os, const std::unordered_map<std::string, std::any>& m) {
for (const auto& [key, value] : m)
os << "{" << key << ": " << value << "}\n";
return os;
}
int main() {
std::unordered_map<std::string, std::any> example = {
{"first", 'A'}, {"second", 2}, {"third", "hai"}
};
std::cout << example;
}