在编译时打印类型的名称而不中止编译?
Print a type's name at compile time without aborting compilation?
本题中:
Print template typename at compile time
我们有一些关于如何让典型的 C++ 编译器在编译时打印类型名称的建议。但是,它们依赖于触发编译错误。
我的问题:我能否让 C++ 编译器在不停止编译的情况下打印类型的名称??
一般来说答案是 "probably not",因为一个有效的程序可以被编译到它的目标对象中而无需在任何地方打印任何东西,所以我特别询问 GCC 和 clang,可能使用预处理器指令,编译器内置函数,或任何特定于编译器的技巧。
备注:
- 显然,挑战在于在
using/typedef
语句、模板参数值、可变模板等后面打印类型。如果类型明确可用,您可以只使用类似 #message "my type is unsigned long long"
的东西(正如@NutCracker 建议的那样).但这不是问题所在。
- 依赖 C++11 或更早版本的答案优于要求 C++14/17/20。
gcc 和 clang 为使用自己的插件提供了一些接口,这些插件几乎可以在从解析到代码生成的不同阶段完成所有工作。
接口是特定于编译器的,因此 gcc 的插件不能用于 clang,反之亦然。
文档很繁琐,这里没有机会详细介绍,所以我只指出 gcc 和 clang 的文档:
以下机制归功于@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)>();
| ~~~~~~~~~~~~~~~~~~~~~~~^~
在 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);
Here 是一个活生生的例子。
本题中:
Print template typename at compile time
我们有一些关于如何让典型的 C++ 编译器在编译时打印类型名称的建议。但是,它们依赖于触发编译错误。
我的问题:我能否让 C++ 编译器在不停止编译的情况下打印类型的名称??
一般来说答案是 "probably not",因为一个有效的程序可以被编译到它的目标对象中而无需在任何地方打印任何东西,所以我特别询问 GCC 和 clang,可能使用预处理器指令,编译器内置函数,或任何特定于编译器的技巧。
备注:
- 显然,挑战在于在
using/typedef
语句、模板参数值、可变模板等后面打印类型。如果类型明确可用,您可以只使用类似#message "my type is unsigned long long"
的东西(正如@NutCracker 建议的那样).但这不是问题所在。 - 依赖 C++11 或更早版本的答案优于要求 C++14/17/20。
gcc 和 clang 为使用自己的插件提供了一些接口,这些插件几乎可以在从解析到代码生成的不同阶段完成所有工作。
接口是特定于编译器的,因此 gcc 的插件不能用于 clang,反之亦然。
文档很繁琐,这里没有机会详细介绍,所以我只指出 gcc 和 clang 的文档:
以下机制归功于@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)>();
| ~~~~~~~~~~~~~~~~~~~~~~~^~
在 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);
Here 是一个活生生的例子。