在std::any 文档的一点帮助下,我想出了这个解决方案。它并不完美,因为您需要为每种类型手动注册打印功能(访问者),但至少您可以使用export_vars
带有对 <string, any> 的容器,并且没有递归模板。
演示
#include <type_traits>
#include <any>
#include <functional>
#include <iomanip>
#include <iostream>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <vector>
template <class T, class F>
inline std::pair<const std::type_index, std::function<void(std::ostream& ostr, std::any const&)>> to_any_visitor(F const& f)
{
return { std::type_index(typeid(T)), [g = f](std::ostream& ostr, std::any const& a) {
if constexpr (std::is_void_v<T>)
g(ostr);
else
g(ostr, std::any_cast<T const&>(a));
} };
}
static std::unordered_map<std::type_index, std::function<void(std::ostream& ostr, std::any const&)>> any_visitor{
to_any_visitor<void>([](std::ostream& ostr) { ostr << "{}"; }),
to_any_visitor<int>([](std::ostream& ostr, int x) { ostr << x; }),
to_any_visitor<unsigned>([](std::ostream& ostr, unsigned x) { ostr << x; }),
to_any_visitor<float>([](std::ostream& ostr, float x) { ostr << x; }),
to_any_visitor<double>([](std::ostream& ostr, double x) { ostr << x; }),
to_any_visitor<char const*>([](std::ostream& ostr, char const* s) { ostr << std::quoted(s); })
};
void export_vars(std::ostream& ostr, const std::vector<std::pair<std::string, std::any>>& args)
{
for (const auto& [name, var] : args)
{
if (const auto it = any_visitor.find(std::type_index(var.type())); it != any_visitor.cend())
{
ostr << name << ": ";
it->second(ostr, var);
ostr << std::endl;
}
else
{
throw std::runtime_error("Print function not registered");
}
}
}
int main()
{
std::vector<std::pair<std::string, std::any>> pairs{ { "xxx", 123.456 }, { "yyy", "some text" }, { "zzz", 789 } };
export_vars(std::cout, pairs);
export_vars(std::cout, {{"xxx", 123}, {"yyy", 5.6}}); // this will also work
}