函数指针 vs 函数作为模板非类型参数

Pointer to function vs function as template non-type parameter

我试图了解以下代码段中发生的事情:

// using FUN = void(*)(void);
using FUN = void(void);

template<FUN fun> struct Fun{};

int main ()
{
    FUN fun;
    Fun<fun>{};
}

我可以使用void(void)作为函数非类型参数,一切正常,程序编译通过。但是,将类型更改为指向函数的指针,即删除第一行中的注释并注释第二行,会导致错误

(g++) error: the value of 'fun' is not usable in a constant expression

(clang) error: non-type template argument of type 'FUN' (aka 'void (*)()') is not a constant expression

到底是怎么回事?函数类型实际上与指向函数的指针不同吗(即,在任何地方都可以隐式转换?)我知道指向函数的指针不应该起作用,因为 FUN fun;main 中它不是常量表达式,但为什么将 FUN 声明为 void(void); 使其起作用?

A non-type template-parameter of type “array of T” or “function returning T” is adjusted to be of type “pointer to T” or “pointer to function returning T”, respectively.

(C++14 中的[temp.param]/8)

因此,模板 Fun 是同一个模板,无论 FUN 被声明为函数还是指向函数类型的指针。

但是,这个块声明:

FUN fun;

根据 FUN 的不同有不同的含义。如果 FUN 是函数,则这是函数的块声明(如果使用 odr,则必须在其他地方定义)。通常,您可以使用函数的名称作为函数指针类型的模板参数的参数——这里没有问题。但是如果 FUN 是一个函数指针,这将创建一个未初始化的函数指针。因为它是一个非 const 对象,所以它不能用作模板参数,就像 int 变量不能用作 int 模板参数但 const int变量可以.