我一直在使用C 中的功能类型进行实验。请注意,我并不是说指针到功能类型:
typedef void (*voidFuncPtr)();
,但更奇特:
typedef void (voidFunc)();
我没想到以下代码会编译,但令人惊讶的是:
template<voidFunc func>
class funcClass
{
public:
void call() { func(); };
};
void func()
{ }
void Test()
{
funcClass<func> foobar;
foobar.call();
}
但是,如果我尝试将以下内容添加到Funcclass:
voidFuncPtr get() { return &func; }
我得到错误 Address expression must be an lvalue or a function designator
我的第一个问题是:编译器使用哪种黑魔法假装它实际上可以通过一个实例来实例?它只是将其当作参考吗?第二个问题是:如果甚至可以称呼它,为什么不能进行地址?另外,这些非销售功能类型是什么?我只是因为boost ::功能而发现了它们,并且从未找到任何有关它们的文档。
§§14.1.4的标准说:
非型模板参数应具有以下(可选的CV合格)类型之一:
- 积分或枚举类型,
- 指向对象的指针或指针function ,[这就是您的是]
- lVALUE引用对象或lVALUE引用功能,
- 指向会员的指针
- std :: nullptr_t。
和§14.1.6说
非类型的非参考模板参数是prvalue。它不会被分配给或以其他方式分配其值。非型非参考模板参数不能将其地址取。当一个非类型非参考模板参数用作初始化供参考,始终使用临时性。
这样解释了您看到的两种行为。
请注意,func
与&func
(§14.3.2.1)相同:
[非类型模板参数可以是一个常数表达式(5.19),该表达式(5.19)指定具有静态存储持续时间和外部或内部链接的对象的地址或具有外部或内部链接的功能,包括功能模板和功能模板ID,但不包括非静态类成员表示(忽略括号)AS&amp;ID表达,除外&amp;如果名称涉及函数或数组,则可能会省略如果相应的模板参数是一个参考;或...
所以这只是一个功能指针。
鉴于没有操作地址和指针(包括功能和成员函数)的代码编译为有效的模板参数,因此编译器认为voidFunc
是函数指针类型,即,该类型的衰减版本。此规则在C 2003和C 2011中没有改变。