非指针函数类型可以是非类型参数吗?

时间:2012-10-19 22:28:18

标签: c++ templates

我一直在用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而发现它们,并且从未能找到任何关于它们的文档。

2 个答案:

答案 0 :(得分:4)

标准的第14.1.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之间的规则没有变化。