例如:
int a = 12;
cout << typeof(a) << endl;
预期输出:
int
原文由 Jorge Ferreira 发布,翻译遵循 CC BY-SA 4.0 许可协议
例如:
int a = 12;
cout << typeof(a) << endl;
预期输出:
int
原文由 Jorge Ferreira 发布,翻译遵循 CC BY-SA 4.0 许可协议
C++ 数据类型在编译时使用模板和运行时使用 TypeId 解析。
编译时解决方案。
template <std::size_t...Idxs>
constexpr auto substring_as_array(std::string_view str, std::index_sequence<Idxs...>)
{
return std::array{str[Idxs]..., '\n'};
}
template <typename T>
constexpr auto type_name_array()
{
#if defined(__clang__)
constexpr auto prefix = std::string_view{"[T = "};
constexpr auto suffix = std::string_view{"]"};
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(__GNUC__)
constexpr auto prefix = std::string_view{"with T = "};
constexpr auto suffix = std::string_view{"]"};
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(_MSC_VER)
constexpr auto prefix = std::string_view{"type_name_array<"};
constexpr auto suffix = std::string_view{">(void)"};
constexpr auto function = std::string_view{__FUNCSIG__};
#else
# error Unsupported compiler
#endif
constexpr auto start = function.find(prefix) + prefix.size();
constexpr auto end = function.rfind(suffix);
static_assert(start < end);
constexpr auto name = function.substr(start, (end - start));
return substring_as_array(name, std::make_index_sequence<name.size()>{});
}
template <typename T>
struct type_name_holder {
static inline constexpr auto value = type_name_array<T>();
};
template <typename T>
constexpr auto type_name() -> std::string_view
{
constexpr auto& value = type_name_holder<T>::value;
return std::string_view{value.data(), value.size()};
}
运行时解决方案。
template <typename T>
void PrintDataType(T type)
{
auto name = typeid(type).name();
string cmd_str = "echo '" + string(name) + "' | c++filt -t";
system(cmd_str.c_str());
}
主要代码
#include <iostream>
#include <map>
#include <string>
#include <typeinfo>
#include <string_view>
#include <array> // std::array
#include <utility> // std::index_sequence
using std::string;
int main() { //Dynamic resolution. std::map<int, int> iMap; PrintDataType(iMap); //Compile type resolution. std::cout << type_name<std::list<int>>() << std::endl; return 0; }
原文由 Haseeb Mir 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
C++11 更新了一个非常古老的问题:在 C++ 中打印变量类型。
公认的(和好的)答案是使用
typeid(a).name()
,其中a
是一个变量名。现在在 C++11 中,我们有
decltype(x)
,它可以将表达式转换为类型。decltype()
有自己的一套非常有趣的规则。例如decltype(a)
和decltype((a))
通常是不同的类型(一旦这些原因暴露出来,出于良好和可理解的原因)。我们可信赖的
typeid(a).name()
会帮助我们探索这个勇敢的新世界吗?不。
但是那个工具并没有那么复杂。这就是我用来回答这个问题的工具。我会将这个新工具与
typeid(a).name()
进行比较和对比。而这个新工具实际上是建立在typeid(a).name()
之上的。根本问题:
丢弃 cv 限定符、引用和左值/右值。例如:
对我来说输出:
我在猜测 MSVC 输出:
即
const
消失了。这不是 QOI(实施质量)问题。该标准规定了这种行为。我在下面推荐的是:
这将像这样使用:
对我来说输出:
<disclaimer>
我没有在 MSVC 上测试过这个。</disclaimer>
但我欢迎那些这样做的人提供反馈。C++11 解决方案
我正在使用
__cxa_demangle
用于非 MSVC 平台,正如 ipapadop 在他对 demangle 类型的回答中所推荐的那样。但在 MSVC 上,我相信typeid
可以解开名称(未经测试)。这个核心围绕着一些简单的测试来检测、恢复和报告 cv-qualifiers 和对输入类型的引用。结果
有了这个解决方案,我可以做到这一点:
输出是:
注意(例如)
decltype(i)
和decltype((i))
之间的区别。前者是i
的 声明 类型。后者是 表达式i
的“类型”。 (表达式从不具有引用类型,但作为惯例decltype
表示具有左值引用的左值表达式)。因此,除了探索和调试您自己的代码之外,此工具是了解
decltype
的绝佳工具。相反,如果我只是在
typeid(a).name()
上构建它,而不添加丢失的 cv 限定符或引用,输出将是:即每个引用和 cv 限定符都被剥离。
C++14 更新
就在您认为自己已经找到了解决问题的方法时,总会有人突然冒出来,向您展示更好的方法。 :-)
Jamboree 的 这个答案 显示了如何在编译时获取 C++14 中的类型名称。这是一个绝妙的解决方案,原因如下:
Jamboree 的 回答 并没有完全说明 VS 的所有内容,我正在稍微调整他的代码。但是由于这个答案得到了很多意见,所以花一些时间去那里并支持他的答案,没有它,这个更新永远不会发生。
如果您仍然停留在古老的 C++11 中,此代码将在
constexpr
上自动退避。如果你用 C++98⁄03 在洞壁上作画,那么noexcept
也会被牺牲掉。C++17 更新
在下面的评论中, Lyberta 指出新的
std::string_view
可以替换static_string
:由于 Jive Dadson 在下面的评论中所做的非常出色的侦探工作,我已经更新了 VS 的常量。
更新:
请务必查看 下面的重写, 它消除了我最新公式中不可读的幻数。