在C ++中创建模板函数时,有一种简单的方法可以将模板的类型名称表示为字符串吗?我有一个简单的测试用例来展示我正在尝试做的事情(注意显示的代码不能编译):
#include <stdio.h>
template <typename type>
type print(type *addr)
{
printf("type is: %s",type);
}
int main()
{
int a;
print(&a);
}
// Would like to print something like:
// type is: int
我认为在实例化函数时,typename应该在编译时可用,但我不熟悉模板,我还没有看到将typename作为字符串的方法。
我想要这样做的原因是一些printf类型的调试。我有多个线程正在运行,并通过gdb逐步更改程序行为。所以对于某些事情,我想转储有关正在执行哪些函数的信息。这不是太重要,所以如果解决方案过于复杂,我会跳过将此信息添加到我的日志记录功能中。但如果有一种简单的方法可以做到这一点,那将是有用的信息。
答案 0 :(得分:52)
获取有用的编译时名称:
假设您有一些名为&#39; T&#39;的未知类型。您可以让编译器通过使用它来打印它的类型。例如:
typedef typename T::something_made_up X;
错误信息如下:
error: no type named 'something_made_up' in 'Wt::Dbo::ptr<trader::model::Candle>'
&#39;&#39;&#39;显示类型。 (仅用clang测试过。)
触发它的其他方式:
bool x = T::nothing; // error: no member named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'
using X = typename T::nothing; // error: no type named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'
使用C ++ 11,您可能已经有了一个对象并使用了'decltype&#39;得到它的类型,所以你也可以运行:
auto obj = creatSomeObject();
bool x = decltype(obj)::nothing; // (Where nothing is not a real member).
答案 1 :(得分:21)
__PRETTY_FUNCTION__
应解决您的问题(至少在运行时间)
以下程序的输出是:
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
!!!Hello World!!!
如果你确实需要将typename作为字符串,你可以破解它(使用snprintf
代替printf
)并在'='之后和']'之前拉出子字符串。
#include <iostream>
using namespace std;
template<typename type>
class test
{
public:
test()
{
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}
};
template<typename type>
void tempFunction()
{
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}
int main() {
test<int> test;
tempFunction<bool>();
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
return 0;
}
答案 2 :(得分:11)
由于您已经说过需要将其用于调试目的,因此也许可以使用运行时解决方案。并且您已将其标记为g ++,因此您不希望成为标准符合。
这就是:
#include <cxxabi.h> // the libstdc++ used by g++ does contain this header
template <typename type>
void print(const type *addr) // you wanted a pointer
{
char * name = abi::__cxa_demangle(typeid(*addr).name(), 0, 0, NULL);
printf("type is: %s\n", name);
free(name);
}
print(new unsigned long); // prints "type is: unsigned long"
print(new std::vector<int>); // prints "type is: std::vector<int, std::allocator<int> >"
编辑:纠正了内存泄漏。谢谢Jesse。
答案 3 :(得分:6)
有Boost.TypeIndex库。
有关详细信息,请参阅boost :: typeindex :: type_id。
它非常易于使用,跨平台,是真正的编译型解决方案。即使没有可用的RTTI,它也可以正常工作。此外,大多数编译器都受到支持。
答案 4 :(得分:1)
另一个编译时解决方案,类似于matiu提供的解决方案,但也许更具描述性的是使用包含在小辅助函数中的static_assert
。
template<typename T>
void print_type_in_compilation_error(T&&)
{
static_assert(std::is_same<T, int>::value && !std::is_same<T, int>::value, "Compilation failed because you wanted to read the type. See below");
}
// usage:
int I;
print_type_in_compilation_error(I);
上面会给你一个很好的错误信息(在MSVC和Clang中测试),如同在另一个答案中,但代码是恕我直言,更好地理解。
答案 5 :(得分:0)
如果您使用已知的一组类型实例化模板,我们可以使用此旧线程中描述的方法: stackoverflow.com/questions/1055452
答案 6 :(得分:0)
正如@chris和@Philipp所评论的那样,除非在编译时确实需要该名称,否则可以在包含typeid(type).name()
之后使用<typeinfo>
。