C++ 带有constexpr函数的模板作为参数返回

C++ 带有constexpr函数的模板作为参数返回,c++,templates,c++11,C++,Templates,C++11,鉴于一些声明: 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()&

鉴于一些声明:

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;
}
模板
结构foo{};
模板
constexpr T ident(T){
返回t;
}
constexpr int bar(){
返回0;
}
int main(int argc,const char*argv[]
{
福阿;
富b;
富科;
福德;
foo e;//不接受(gcc 4.7.2在此甚至崩溃)
返回0;
}
旁白:有趣的是,这在GCC4.7.2中导致了一个SEGFULT。我不得不在我的svn构建的4.8.0快照中运行它,甚至得到一条错误消息(“必须是具有外部链接的函数的地址”)


为什么第一个是可以的,而最后一个是不允许的-这不是康斯特普勒像案例a-d吗?编译器似乎完全能够确定哪个函数是
ident(&bar)
,因为它可以对其他类型执行此操作。

E的问题是,对于指向函数的指针类型的非类型模板参数,必须使用它的地址(14.3.2)。例如,
foo
无效。因此,即使
ident(bar)
的返回是指向具有有效外部链接的函数的指针,对于非类型模板参数,表达式作为一个整体是无效的。如果您从
ident(bar)
返回了0(或nullptr),它将被编译(也在14.3.2中定义)


该标准允许您省略函数指针类型上的&,但它仍然必须是有效的,才能获取它的地址。这就是为什么
foo
有效,因为
foo
是有效的。另一个函数调用B、C(和A)求值为整数常量,这属于不同的类别。

从C++17开始允许这样做;请参阅(最近的投票文件,C++的标准)。Clang trunk在
-std=c++1z
模式下接受您的代码。

错误消息是什么?什么是baz?啊。下次,给我们一个最小的复制测试用例。把你的bug报告交给GCC bug追踪器,好吗?这是一块冰。对于我来说,G++4.7给出了:“
ident(baz)
不是类型
int(*)(
)的有效模板参数;它必须是具有外部链接的函数的地址”。@sftrabbit修复了该示例。它结冰了。结束时不是一个真正的问题直觉告诉我,你所尝试的与
std::forward
解决的问题类似:关于
&bar
的一些东西在
ident
中发生了变化。