为什么指向__func__的指针无法作为C++模板参数?
报错原因
1. 指针类非类型模板参数的硬性要求
C++标准明确规定,指针类型的非类型模板参数仅接受以下几类值:
- 空指针常量
- 指向具有链接属性的对象/函数的地址(C03要求必须是外部链接,C11起新增支持内部链接)
- 指向类成员的指针
2. __func__的链接属性不符合要求
GCC文档描述的static const char __func__[] = "function-name";是函数块作用域内的静态变量,这类变量属于无链接实体,和命名空间作用域下的静态数组性质完全不同:命名空间下的static变量属于内部链接,符合C++11及之后的模板参数要求,而块作用域的静态变量没有任何链接属性,地址不能作为模板参数使用。
3. constexpr修饰无法规避限制
你用constexpr const char*存储__func__的地址,只是保证了指针值本身是编译期可计算的,但指针指向的实体的链接属性不符合要求,所以依然编译失败。而nullptr是空指针常量,不需要指向任何实体,所以可以正常传入。
可行替代方案
- 方案1:C++20及以上版本使用编译期字符串包装
自定义支持编译期构造的固定长度字符串类作为非类型模板参数,将__func__的内容拷贝到类实例中传入模板:template<size_t N> struct FixedStr { char buf[N]{}; constexpr FixedStr(const char(&s)[N]) noexcept { for (size_t i = 0; i < N; ++i) buf[i] = s[i]; } }; template<FixedStr Str> struct MyStruct {}; int main() { MyStruct<__func__> s; // C++20及以上可正常编译 } - 方案2:配合宏传递字符串字面量
如果不需要严格的标准兼容性,可通过宏将函数名转为字符串字面量传入,适配低版本编译器:// 函数声明宏自动提取函数名字面量 #define DEFINE_FUNC(ret_type, func_name, ...) \ ret_type func_name(__VA_ARGS__) { \ static constexpr const char func_name_str[] = #func_name; \ MyStruct<func_name_str> s{}; - 方案3:改为普通参数传递
如果不需要用函数名区分模板类型,只是需要在模板逻辑中使用函数名字符串,直接将__func__作为构造函数参数传入即可,没有编译限制。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

