8

在这个问题中:

在编译时打印模板类型名

我们有一些关于如何让典型的 C++ 编译器在编译时打印类型名称的建议。但是,它们依赖于触发编译错误。

我的问题:我可以让 C++ 编译器在停止编译的情况下打印类型的名称吗?

一般来说,答案是“可能不是”,因为可以将有效程序编译到其目标对象中而无需在任何地方打印任何内容,所以我特别询问 GCC 和 clang,可能使用预处理器指令、编译器内置程序或任何编译器- 特定的技巧。

笔记:

  • 显然,挑战是在语句、模板参数值、可变参数模板等后面打印类型using/typedef。如果类型明确可用,您可以使用类似的东西#message "my type is unsigned long long"(如@NutCracker 建议的那样)。但这不是问题所在。
  • 依赖 C++11 或更早版本的答案优于要求 C++14/17/20 的答案。
4

3 回答 3

1

以下机制归功于@JonathanWakely,并且特定于 GCC:

int i;

template <typename T>
[[gnu::warning("your type here")]]
bool print_type() { return true; }

bool b = print_type<decltype(i)>();

这给了你:

<source>:In function 'void __static_initialization_and_destruction_0(int, int)':
<source>:7:33: warning: call to 'print_type<int>' declared with attribute warning: your
type here [-Wattribute-warning]
    7 | bool b = print_type<decltype(i)>();
      |          ~~~~~~~~~~~~~~~~~~~~~~~^~

看到它在 Godbolt 上工作

于 2020-02-14T11:26:46.520 回答
1

gcc 和 clang 提供了一些使用自己的插件的接口,这些插件几乎可以在从解析到代码生成的不同阶段完成所有工作。

接口是编译器特定的,因为这是 gcc 的插件不能用于 clang,反之亦然。

文档很繁琐,这里没有机会详细介绍,所以我只向您指出来自 gcc 和 clang 的文档:

gcc 插件 clang 插件

于 2020-02-13T12:02:47.897 回答
1

在 c++17 中,我们可以滥用该[[deprecated]]属性来强制编译器发出包含所需模板参数的警告:

template<typename T>
[[deprecated]] inline constexpr void print_type(T&& t, const char* msg=nullptr){}

print_type(999, "I just want to know the type here...");

上面的代码片段将使用 gcc 打印以下警告:

<source>:32:59: warning: 'constexpr void print_type(T&&, const char*) [with T = int]' is deprecated [-Wdeprecated-declarations]
     print_type(999, "I just want to know the type here...");

与接受的答案相反,这将适用于每个符合 c++17 的编译器。请注意,您必须在 MSVC 上启用 \W3`。

我们甚至可以更进一步,定义一个静态断言宏,当且仅当它失败时才会打印类型。

template<bool b, typename T>
inline constexpr bool print_type_if_false(T&& t) {
    if constexpr (!b)
        print_type(std::forward<T>(t));
    return b;
}

// Some nice static assert that will print the type if it fails.
#define STATIC_ASSERT(x,condition, msg) static_assert(print_type_if_false<condition>(x), msg);

是一个活生生的例子。

于 2021-01-18T10:39:07.787 回答