我正在尝试了解以下代码段中发生了什么:
// using FUN = void(*)(void);
using FUN = void(void);
template<FUN fun> struct Fun{};
int main ()
{
FUN fun;
Fun<fun>{};
}
我可以使用void(void)
作为函数非类型参数,一切都很好,程序编译。但是,将类型更改为指向函数的指针,即删除第一行中的注释并注释第二行,会导致错误
( g ++ )错误:'fun'的值在常量表达式中不可用
( clang )错误:类型为'FUN'的非类型模板参数(又名'void(*)()') 不是一个恒定的表达
究竟发生了什么?函数类型实际上是否与指向函数的指针相同(即,可以在任何地方隐式转换?)我理解指向函数的指针不起作用,因为FUN fun;
中的main
它不是常数表达式,但为什么将FUN
声明为void(void);
使其有效?
答案 0 :(得分:3)
类型为“
T
数组”或“函数返回T
”的非类型模板参数被调整为类型 “指向T
的指针”或“指向函数返回T
的指针”。
(C ++ 14中的[temp.param] / 8)
因此,模板Fun
是相同的模板,无论FUN
是声明为函数还是指向函数类型的指针。
但是,这个块声明:
FUN fun;
具有不同的含义,具体取决于FUN
。如果FUN
是一个函数,那么这是一个函数的块声明(如果使用了odr,必须在其他地方定义)。通常,您可以使用函数的名称作为函数指针类型的模板参数的参数---这里没有问题。但是如果FUN
是函数指针,则会创建一个未初始化的函数指针。由于它是非const
对象,因此不能将其用作模板参数,因为int
变量不能用作int
模板参数的模板参数,一个const int
变量可以。