鉴于一些声明:
template <class T, T t>
struct foo {};
template <class T>
constexpr T ident(T t) {
return t;
}
constexpr int bar() {
return 0;
}
int main(int argc, const char *argv[])
{
foo<bool, true> a;
foo<int, bar()> b;
foo<int, ident(0)> c;
foo<int (*)(), bar> d;
foo<int(*)(), ident(&bar)> e; // not accepted (gcc 4.7.2 crashes here, even)
return 0;
}
除此之外:有趣的是,这导致了gcc 4.7.2的段错误。我不得不通过我的svn版本的4.8.0快照运行它甚至得到一条错误消息(“必须是带有外部链接的函数的地址”)......
为什么第一个OK,最后一个不允许 - 这个constexpr不是像a-d那样吗?似乎编译器完全能够确定ident(&bar)
正在讨论哪个函数,因为它可以为其他类型执行。
答案 0 :(得分:2)
答案 1 :(得分:1)
E的问题在于,对于非类型模板参数,类型为指针的函数,它必须有效才能获取它的地址(14.3.2)。例如,foo<int(*)(), &ident(bar)>
无效。因此,即使ident(bar)
的返回是指向具有有效外部链接的函数的指针,对于非类型模板参数,整个表达式也是无效的。如果您从ident(bar)
返回0(或nullptr),它将被编译(也在14.3.2中定义)。
该标准允许您省略&amp;在一种指向函数的指针上,但它仍然必须有效才能获取它的地址。这就是foo<int (*)(), bar>
有效的原因,因为foo<int (*)(), &bar>
有效。另一个函数调用B,C(和A)求值为整数常量,它们属于不同的类别。