在回答this question时,我尝试使用gcc(code compiled)和clang(code rejected)执行以下代码:
typedef long (*func)(int);
long function(int) { return 42; }
struct Test
{
static constexpr func f = &function;
};
template<func c>
struct Call
{
static void f()
{
c(0);
}
};
int main()
{
Call<Test::f>::f();
}
我不确定哪个编译器是正确的,尽管我认为Test::f
的constexpr初始化是可以的。错误clang输出是:
error: non-type template argument for template parameter of pointer type 'func'
(aka 'long (*)(int)') must have its address taken
编辑:对于&#34;为什么&#34;,请参阅DyP's question。
答案 0 :(得分:9)
14.3.2模板非类型参数[temp.arg.nontype]
非类型非模板模板参数的模板参数应为以下之一:
[...]
- 一个常量表达式(5.19),用于指定具有静态存储的对象的地址&gt;持续时间和外部或内部链接或具有外部或内部链接的函数,包括函数模板和函数模板-id,但不包括非静态类成员,表示(忽略括号)为&amp; id-expression ,除了&amp;如果名称引用函数或数组,则可以省略,如果相应的模板参数是引用,则应省略; [...]
(n3485,强调我的)
我不知道为什么它受到限制,但我认为它可能与函数地址在编译时不可用的事实有关(可能有替代模板实例化的目的)。
编辑:由于Synxis的后续问题(评论)而增强了答案
constexpr func = &function;
^这是良好的形式;您可以使用函数的地址初始化constexpr
对象。
问题是明确禁止将指针用作非类型模板参数而不是&identifier
形式:
using My_Call = Call < &function >; // fine
constexpr func mypointer = &function; // fine
using My_Ind_Call = Call < func >; // forbidden, argument not of form `&id`