我们如何打印出C++ STL 容器的value_type?
How do we print out the value_type of a C++ STL container?
我知道 STL 容器有一个value_type
参数,并且我已经看到了如何使用它来声明变量的类型,例如:
vector<int>::value_type foo;
但是我们可以只将此value_type
打印到控制台吗?
我想在这个例子中看到"字符串":
int main() {
vector<string> v = {"apple", "facebook", "microsoft", "google"};
cout << v << endl;
cout << v.value_type << endl;
return 0;
}
在这方面X::value_type
与任何其他类型别名(又名typedef(没有什么不同——C++没有将类型转换为其源代码字符串表示的本机方法(尤其是因为这可能是模棱两可的(。您可以做的是使用std::type_info::name
:
cout << typeid(decltype(v)::value_type).name() << endl;
生成的文本依赖于编译器(甚至不能保证易于人类阅读(。它将在程序的同一版本中保持一致,但您不能期望它在不同的编译器中是相同的。换句话说,它对于调试很有用,但不能可靠地以持久方式使用。
除了基于typeid
的答案之外,我还看到了使用 Boost 的另一种可能性,如下所示:
#include <boost/type_index.hpp>
cout << boost::typeindex::type_id_with_cvr<decltype(v)::value_type>().pretty_name() << "n";
优点是可移植的、人类可读的名称,其中包括常量/易失性限定,并且在主要编译器和系统中保持一致。我的机器上的输出是
// when compiled with gcc:
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
// ... and with clang:
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
自己决定此输出是否符合"人类可读"的条件,但也将其与typeid(...).name()
方法进行比较,该方法在我的机器上给出:
NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
假设您需要此类型信息进行调试可能是安全的(?(。 如果是,不要忘记 gdb 内置的whatis
和ptype
命令:
$ cat main.cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<string> v = {"apple", "facebook", "microsoft", "google" };
cout << v[2] << endl;
// cout << v.value_type << endl;
return 0;
}
$ cat gdbCommands.txt
break main
run
next
next
whatis v
quit
$ g++ -ggdb -o main main.cpp
$ gdb -x gdbCommands.txt ./main
GNU gdb (Ubuntu 8.0.1-0ubuntu1) 8.0.1
// bla bla bla ...
type = std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >>
前段时间我有一个相当类似的问题。那里的答案显示了一个能够将类型转换为人类可读字符串的函数:
template <typename T> std::string TypeName() {
auto name = typeid(T()).name(); // function type, not a constructor call!
int status = 0;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
std::string ret((status == 0) ? res.get() : name);
if (ret.substr(ret.size() - 3) == " ()") ret.resize(ret.size() - 3);
return ret;
}
一旦你有了这个TypeName
功能,你就可以实现你的目标:
int main() {
vector<string> v = {"apple", "facebook", "microsoft", "google" };
cout << v << endl;
cout << TypeName<v.value_type>() << endl;
return 0;
}
哪个应该输出(GCC HEAD 9 201809(:
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
如果用于调试目的,则此解决方案将在没有任何依赖项的情况下工作:
#include <regex>
template <typename T>
struct TypeToNameT
{
static std::string getTypeFromName() {
#ifdef _MSC_VER
std::regex re("<(.*)>::.*");
std::string templateType(__FUNCTION__);
#else
std::regex re(" = (.*);");
std::string templateType(__PRETTY_FUNCTION__);
#endif
std::smatch match;
try
{
if (std::regex_search(templateType, match, re) && match.size() > 1)
return match.str(1);
}
catch (std::regex_error& e) {
// Syntax error in the regular expression
}
return "";
}
};
/** Get the templated type name. This does not depends on RTTI, but on the preprocessor, so it should be quite safe to use even on old compilers */
template <typename T>
std::string getTypeName() { return TypeToNameT<T>::getTypeFromName(); }
int main() {
std::vector<std::string> v = {"apple", "facebook", "microsoft", "google" };
std::cout << getTypeName<decltype(v)::value_type>() << std::endl; // Returns: "std::__cxx11::basic_string<char>"
return 0;
}
与基于typeid
的答案不同,它使用预处理器,因此不受名称重整的影响(因此名称是......可读(。
请注意,您不能直接将v.value_type
用作类型,它不是实例v
的一部分,而是v
类型:std::vector<std::string>
正则表达式部分是因为std::string
类太笨了,你需要这样的奇怪来做一个简单的搜索/拆分代码。如果你有一个不错的字符串类,这里不需要正则表达式来提取"="字符串之后和";"之前的部分。
- 瓦尔格林德:数学函数"Conditional jump or move depends on uninitialised value(s)"
- 使用 [] 运算符时"binding reference of type discards qualifiers"
- 为什么static_assert错误:即使我传递常量"expression must have a constant value"?
- 在 QVector<std::unique_ptr 上使用 std::find<Type>>
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 使用 cmake 的 Linux 终端上的"Conversion to non-scalar type is requested"错误
- 控制到达非空函数clang(-Wreturn-type)的末尾
- 为什么我会" void value not ignored as it ought to be"?
- std::unordered_map 类型对象声明期间出现"field has incomplete type"错误
- 方法错误"not all control paths return a value"和方法不返回值
- 将系数存储在头文件的数组中("does not name a type"错误)
- 尝试打开 ifstream 时出现"Incomplete type"错误
- C++/SDL "initial value of reference to a non-const must be an lvalue"
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- 在"结构提升::enable_if<提升::is_pod<T>,无效>"中没有名为"type"的类型
- 如何修复" State Error (active) E0513 a value of type "const wchar_t *" cannot be assigned to an entity o
- "a value of type " void (exeCallback::*)(int) " cannot be assigned to an entity of type " void (*)(
- cmake -D <var>:<type>=<value> 参数"-D"是什么意思
- 没有用于初始化'value type'的匹配构造函数
- new(size, value) Type[0]返回的指针是否合法,是否可以用来构建数组?