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

时间:2013-03-04 13:43:51

标签: 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()> 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)正在讨论哪个函数,因为它可以为其他类型执行。

2 个答案:

答案 0 :(得分:2)

从C ++ 17开始,这是允许的;请参阅N4198(以及最近投票进入C ++标准的相应措辞文件N4268)。 Clang trunk以-std=c++1z模式接受您的代码。

答案 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)求值为整数常量,它们属于不同的类别。

相关问题