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

时间:2015-10-08 22:50:15

标签: c++ templates function-pointers

我正在尝试了解以下代码段中发生了什么:

// 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);使其有效?

1 个答案:

答案 0 :(得分:3)

  

类型为“T数组”或“函数返回T”的非类型模板参数被调整为类型   “指向T的指针”或“指向函数返回T的指针”。

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

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

但是,这个块声明:

FUN fun;

具有不同的含义,具体取决于FUN。如果FUN是一个函数,那么这是一个函数的块声明(如果使用了odr,必须在其他地方定义)。通常,您可以使用函数的名称作为函数指针类型的模板参数的参数---这里没有问题。但是如果FUN是函数指针,则会创建一个未初始化的函数指针。由于它是非const对象,因此不能将其用作模板参数,因为int变量不能用作int模板参数的模板参数,一个const int变量可以。