输出地图对象,其中值可以是任何数据类型

output map object where the value can be any data type

正在尝试输出一个地图对象,其中的值可以是任何数据类型。尝试了以下方法:

#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;
}

但是,获取值的无限循环。

没有打印任意 std::unordered_map<std::string, std::any> 内容的好方法。它可能包含不可打印的内容,并且您已经丢弃了有关内容实际类型的信息。您需要将该信息保存在某个地方。

#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;
}

See it on coliru

另一种方法是将每种类型对应的打印函数注册到散列table中,并使用type_index(any::type)作为运行时访问相应打印函数的键。

#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;
}

Demo.