为什么不允许使用0作为void*的默认非类型模板参数

Why using 0 as default non type template parameter for void* is not allowed

本文关键字:默认 类型 参数 不允许 void 作为 为什么      更新时间:2023-10-16

为什么下面的代码无法编译?尽管void* ptr = 0;

是合法的
template <void* ptr = 0>
void func();
int main() {
    func();
    return 0;
}

我问这个问题是因为我发现一个非常可信的源代码做了类似的事情,并且在我的机器上无法编译

注意应该在我的问题中发布编译器错误,所以这里是

so_test.cpp:1:23: error: null non-type template argument must be cast to template parameter type 'void *'
template <void* ptr = 0>
                      ^
                      static_cast<void *>( )
so_test.cpp:1:17: note: template parameter is declared here
template <void* ptr = 0>
                ^
so_test.cpp:5:5: error: no matching function for call to 'func'
    func();
    ^~~~
so_test.cpp:2:6: note: candidate template ignored: substitution failure [with ptr = nullptr]: null non-type template argument must be cast to template parameter type 'void *'
void func();
     ^

不允许使用void*类型的模板参数。参见标准中的[temp.param]/4,也总结在http://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter

非类型模板参数应具有以下类型之一(可选cv-qualified):

  • 整型或枚举型,
  • 指向对象或指向函数的指针,
  • 左值指向对象或左值指向函数
  • 指针指向成员,
  • std::nullptr_t .

由于void不是对象或函数类型,因此void*不在允许的类型之列。

附录:编译时已知的void*值不是很有用。不可能在编译时检查它的值,因为reinterpret_cast不允许在常量表达式中使用;也不可能在编译时将某些对象类型T转换为T*

您尝试使用int初始化指针。许多隐式转换,包括整型到指针的转换,都不会在非类型模板形参中发生。

c++ 14中指向对象类型的指针的非模板形参的行为的cppreference总结为:

对于指向对象的指针,模板实参必须指定具有静态存储时间和链接(内部或外部)的对象的地址,或者指定计算结果为适当的空指针或std::nullptr_t值的常量表达式。

所以代码可以是:

template <void* ptr = nullptr>
void f();

脚注:似乎不清楚void *是否被允许作为参数类型,但编译器接受上述代码。