【发布时间】:2015-03-10 15:21:04
【问题描述】:
考虑这个程序:
template <int F(), int N = F()>
void f() { }
constexpr int g() { return 1; }
int main() { f<g>(); }
这有效吗?编译器是否需要在模板定义时查看 F 可能引用 constexpr 函数,因此 N 的默认参数可能有效?
gcc 和 clang 接受这一点,但 Intel1 在模板定义时拒绝模板函数,因为 F() 不是常量表达式。如果删除了默认参数,英特尔确实接受f<g, g()>(),因此它清楚地理解g() 通常可用于常量表达式。
我不清楚标准是怎么说的。很明显 (C++11 [expr.const]p2)
对文字类或
constexpr函数的constexpr构造函数以外的函数的调用
呈现一个非常量的表达式,但我不清楚这是否适用于这里。在模板定义时,它似乎确实适用,因为 F 没有被声明为 constexpr 函数,但同时,模板定义时的错误应该只有在没有可能的有效时才被诊断出来模板的实例化,并且这里似乎确实有一个有效的实例化。
我可以看到两个答案的论点,所以我很困惑。这个问题有确定的答案吗?
1. 使用当前版本的英特尔编译器重新测试表明它工作得很好,因此英特尔开发人员可能认为这是一个错误并已修复它。这是一个巨大的暗示,表明代码是有效的。不过,根据标准得到一个结论性的答案仍然很好。
【问题讨论】:
-
旁注:已调整为指向函数的指针。
-
我猜这是不正确的,因为
F()不是constexpr所以不符合 [temp.arg.nontype] 的“常量表达式”。跨度> -
可能相关? N4198
-
@T.C.当然。对函数的引用以相同的方式工作,FWIW:被 gcc 和 clang 接受,被 Intel 拒绝。
-
@dyp 嘿,很好。
template <typename T> int f(); template <> constexpr int f<int>() { return 0; } template <typename T, int N = f<T>()> int g() { return N; } int main() { return g<int>(); }产生“内部错误:断言失败:“shared/cfe/edgcpfe/exprutil.c”,第 11056 行”。 :)
标签: c++ templates c++11 language-lawyer constexpr