我一直在用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
我的第一个问题是:编译器使用什么样的黑魔法假装func类型实际上可以绕过一个实例?它只是把它当作参考吗?第二个问题是:如果它甚至可以被调用,为什么不能采取它的地址?另外,这些非指针函数类型被称为什么?我只是因为boost :: function而发现它们,并且从未能找到任何关于它们的文档。
答案 0 :(得分:4)
非类型模板参数应具有以下(可选的cv限定)类型之一:
- 整数或枚举类型,
- 指向对象的指针或指向函数的指针,[这就是你的]
- 对对象的左值引用或对函数的左值引用,
- 指向成员的指针,
- std :: nullptr_t。
§14.1.6说
非类型非参考模板参数是prvalue。它不应该 被分配或以任何其他方式改变其价值。 非类型 非参考模板参数不能使用其地址。当一个 非类型非参考模板参数用作初始化器 作为参考,总是使用临时。
这样就解释了你所看到的两种行为。
请注意,func
与&func
(§14.3.2.1)相同:
[非类型模板参数可以]是一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址或 具有外部或内部联动功能,包括功能 模板和函数template-id但不包括非静态类 成员,表达(忽略括号)为&amp; id-expression,除了 &amp;如果名称引用函数或数组,则可以省略 如果相应的模板参数是a,则应省略 参考;或...
所以它只是一个函数指针。
答案 1 :(得分:2)
鉴于代码编译时没有address-of运算符和指针(包括函数和成员函数)是有效的模板参数,编译器似乎认为voidFunc
是函数指针类型,即衰减该类型的版本。 C ++ 2003和C ++ 2011之间的规则没有变化。