如何在C++运行时获取并打印variant中包含的类型?
在C++中运行时打印std::variant的类型(结合pybind11场景)
一、纯C++环境下打印std::variant的类型
核心思路是用std::visit遍历variant的所有可能类型,结合typeid获取类型信息。需要注意的是,GCC/Clang会输出经过名字修饰的类型名,需额外解析为可读格式;MSVC则直接输出友好的类型名称。
实现代码
#include <variant> #include <iostream> #include <typeinfo> #include <string> struct VariantTypePrinter { template<typename T> void operator()(const T&) const { #ifdef __GNUC__ int status; // 解析GCC/Clang的名字修饰字符串 char* demangled = __cxxabiv1::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status); if (status == 0) { std::cout << demangled << std::endl; free(demangled); } else { std::cout << typeid(T).name() << std::endl; } #else // MSVC直接输出可读类型名 std::cout << typeid(T).name() << std::endl; #endif } }; // 使用示例 int main() { std::variant<int, float, std::string, bool> var = 3.14f; std::visit(VariantTypePrinter{}, var); // 输出float(GCC解析后) return 0; }
二、结合pybind11的场景处理
从Python字典传递值到C时,有两种常见需求:打印Python端的原生类型,或者打印转换为C std::variant后的类型。
1. 直接打印Python对象的类型
通过pybind11的py::object直接获取Python层面的类型名称:
#include <pybind11/pybind11.h> namespace py = pybind11; void print_python_type(const py::object& obj) { // 获取Python类型的__name__属性 std::cout << obj.attr("__class__").attr("__name__").cast<std::string>() << std::endl; }
2. 转换为std::variant后打印C++类型
先将Python值转换为C++的std::variant,再用之前的VariantTypePrinter打印:
#include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <variant> #include <iostream> namespace py = pybind11; struct VariantTypePrinter { template<typename T> void operator()(const T&) const { #ifdef __GNUC__ int status; char* demangled = __cxxabiv1::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status); if (status == 0) { std::cout << demangled << std::endl; free(demangled); } else { std::cout << typeid(T).name() << std::endl; } #else std::cout << typeid(T).name() << std::endl; #endif } }; void process_python_dict(const py::dict& dict) { for (auto& [key, value] : dict) { std::cout << "Key (Python type): "; print_python_type(key); std::cout << "Value (Python type): "; print_python_type(value); // 转换Python值到C++ variant(可根据需求扩展支持的类型) std::variant<int, float, std::string, bool> cpp_var; if (py::isinstance<py::int_>(value)) { cpp_var = value.cast<int>(); } else if (py::isinstance<py::float_>(value)) { cpp_var = value.cast<float>(); } else if (py::isinstance<py::str>(value)) { cpp_var = value.cast<std::string>(); } else if (py::isinstance<py::bool_>(value)) { cpp_var = value.cast<bool>(); } std::cout << "Value (C++ variant type): "; std::visit(VariantTypePrinter{}, cpp_var); std::cout << "---" << std::endl; } } PYBIND11_MODULE(type_printer, m) { m.def("process_dict", &process_python_dict, "Process Python dict and print types"); }
注意事项
typeid(T).name()的输出格式依赖编译器,GCC/Clang需要用__cxa_demangle解析,MSVC无需额外处理。- 若需要支持更多Python类型(如列表、嵌套字典),可以扩展std::variant的类型列表,或直接处理pybind11的
py::list、py::dict类型。 - 直接获取Python的类型名称更贴合Python端的类型认知,转换为C++ variant后打印的是对应的C++类型。
内容的提问来源于stack exchange,提问作者Contango
相关产品推荐
相关产品推荐

