C++ 在编译时打印模板类型名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9813316/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:18:37  来源:igfitidea点击:

Print template typename at compile time

c++g++

提问by Gabriel Southern

When creating a template function in C++ is there a simple way to have the typename of the template represented as a string? I have a simple test case to show what I'm trying to do (note the code shown does not compile):

在 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

I think that the typename should be available at compile time when the function is instantiated, but I'm not that familiar with templates and I haven't seen a way to get the typename as a string.

我认为当函数被实例化时,typename 应该在编译时可用,但我对模板不太熟悉,我还没有看到将 typename 作为字符串获取的方法。

The reason that I want to do this is for some printf type debugging. I have multiple threads running and stepping through with gdb changes the program behavior. So for some things I want to dump information about which functions were executing. It's not too important so if the solution is overly complex I would skip adding this information to my logging function. But if there was a simple way to do this it would be useful information to have.

我想这样做的原因是为了一些 printf 类型的调试。我有多个线程在运行,并且使用 gdb 单步执行会更改程序行为。因此,对于某些事情,我想转储有关正在执行哪些函数的信息。这不是太重要,所以如果解决方案过于复杂,我会跳过将此信息添加到我的日志记录功能。但是,如果有一种简单的方法可以做到这一点,那将是有用的信息。

采纳答案by David D

__PRETTY_FUNCTION__should solve your problem (at run time at least)

__PRETTY_FUNCTION__应该可以解决您的问题(至少在运行时)

The output to the program below is:

下面程序的输出是:

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!!!

If you really, really, need the typename as a string, you could hack this (using snprintfinstead of printf) and pull the substring after '=' and before ']'.

如果你真的,真的,需要类型名作为字符串,你可以破解这个(使用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;
}

回答by matiu

To get a useful compile time name:

要获得有用的编译时名称:

Supposing you have some unknown type named 'T'. You can get the compiler to print it's type by using it horribly. For example:

假设您有一些名为“T”的未知类型。您可以通过可怕地使用它来让编译器打印它的类型。例如:

typedef typename T::something_made_up X;

The error message will be like:

错误消息将类似于:

error: no type named 'something_made_up' in 'Wt::Dbo::ptr<trader::model::Candle>'

The bit after 'in' shows the type. (Only tested with clang).

'in' 后面的位显示类型。(仅用 clang 测试过)。

Other ways of triggering it:

其他触发方式:

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>'

With C++11, you may already have an object and use 'decltype' to get its type, so you can also run:

使用 C++11,您可能已经拥有一个对象并使用 'decltype' 获取其类型,因此您还可以运行:

auto obj = creatSomeObject();
bool x = decltype(obj)::nothing; // (Where nothing is not a real member). 

回答by ipc

Since you have said you would need this for debugging purpose, maybe a runtime solution is also acceptable. And you have tagged this as g++ so you don't want to be standard conform.

既然你说过你需要这个用于调试目的,也许运行时解决方案也是可以接受的。而且您已将其标记为 g++,因此您不想符合标准。

Here is what that means:

这是什么意思:

#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);
  delete name;
}

print(new unsigned long);    // prints "type is: unsigned long"
print(new std::vector<int>); // prints "type is: std::vector<int, std::allocator<int> >"

EDIT: corrected the memory leak. Thx to Jesse.

编辑:更正了内存泄漏。谢谢杰西。

回答by Andrey

There is Boost.TypeIndex library.

有 Boost.TypeIndex 库。

See boost::typeindex::type_id for details.

有关详细信息,请参阅 boost::typeindex::type_id。

It is very-easy-to-use, cross-platform and is real compile-type solution. Also it works as well even if no RTTI available. Also most of compilers are supported from the box.

它非常易于使用,跨平台,是真正的编译型解决方案。即使没有可用的 RTTI,它也能正常工作。此外,大多数编译器都支持开箱即用。

回答by florestan

Another compile time solution, similar to the one provided by matiu, but perhaps a little more descriptive would be to use a static_assertwrapped in a little helper function.

另一种编译时解决方案,类似于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);

The above will give you a nice error message (tested in MSVC and Clang) as in the other answer, but the code is IMHO better to understand.

以上将为您提供一个很好的错误消息(在 MSVC 和 Clang 中测试),就像在另一个答案中一样,但恕我直言,代码更易于理解。

回答by Marius

if you have a known set of types used instantiate the template we can use the approach described in this older thread: stackoverflow.com/questions/1055452

如果您有一组已知的类型用于实例化模板,我们可以使用此旧线程中描述的方法: stackoverflow.com/questions/1055452