4

我一直在试验 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 而发现了它们,并且从来没有找到任何关于它们的文档。

4

2 回答 2

4

标准的§14.1.4 说:

非类型模板参数应具有以下类型之一(可选 cv 限定):

— 整数或枚举类型,

— 指向对象的指针或指向函数的指针,[这是你的]

— 对对象的左值引用或对函数的左值引用,

— 指向成员的指针,

— std::nullptr_t。

§14.1.6 说

非类型非引用模板参数是纯右值。它不应被分配或以任何其他方式更改其值。非类型非引用模板参数不能获取其地址。当使用非类型非引用模板参数作为引用的初始化器时,总是使用临时的。

这解释了你看到的两种行为。

请注意,func这与&func(§14.3.2.1)相同:

[非类型模板参数可以是]一个常量表达式(5.19),它指定具有静态存储持续时间和外部或内部链接的对象或具有外部或内部链接的函数的地址,包括函数模板和函数模板ID,但不包括非静态类成员,表示(忽略括号)为 & id-expression,但如果名称引用函数或数组,则 & 可以省略, 如果相应的模板参数是引用,则 & 应省略;或者...

所以它只是一个函数指针。

于 2012-10-19T22:39:37.907 回答
2

鉴于代码在没有地址运算符的情况下编译,并且指针(包括函数和成员函数)是有效的模板参数,编译器似乎认为voidFunc是函数指针类型,即类型的衰减版本。这方面的规则在 C++ 2003 和 C++ 2011 之间没有改变。

于 2012-10-19T22:39:26.407 回答