这个错误信息正确吗:非类型模板参数不是常量表达式。

19

以下程序在GCC 5.2下可以编译,但在clang 3.6下无法编译:

constexpr bool flag();

template <bool b = flag()>
constexpr bool test() 
{ 
    return b;
}

int main() 
{
}

我在使用clang时收到的错误信息是:

main.cpp:3:20: error: non-type template argument is not a constant expression
template <bool b = flag()>
                   ^~~~~~
main.cpp:3:20: note: undefined function 'flag' cannot be used in a constant expression
main.cpp:1:16: note: declared here
constexpr bool flag();
               ^
main.cpp:4:16: error: no return statement in constexpr function
constexpr bool test() 
               ^

我的问题是:谁是正确的?换句话说,这个程序是否格式不正确?


1
可以确认这一点,即使是clang 3.7也无法编译它。然而,如果你在“constexpr bool flag()”中加入一个返回语句,它就能工作了。 - vsoftco
1
我认为这与您关于默认模板参数被评估的点的其他问题有关:如果它们在定义点被评估,那么clang无法证明该模板在[temp.res]p8下是不良形式的。 - dyp
为什么在一个无返回值函数中有一个返回语句?我还可以确认这在MSVS 2015上编译。 - NathanOliver
3
对不起,我有点困惑。当然可以有此模板的有效特化。因此问题是,您是否可以提供无效的默认模板参数。这与CWG 2008CWG 1850有关,但我没有看到完全回答。成员模板中也有类似的问题,这表明clang允许拒绝OP的程序。 - dyp
2
我很高兴自己不是靠写C++编译器为生的。 - Mark Ransom
显示剩余3条评论
2个回答

5
我会说clang是正确的:
从标准上来看:
[temp.param] 14.1 #9
9个默认模板参数是指在模板参数中在=之后指定的模板参数。[...]
而[temp.arg.nontype] 14.3.2
1个非类型模板参数的模板参数必须是具有转换常量表达式(5.20)的类型。
而[expr.const] 5.20
2个条件表达式e是核心常量表达式,除非根据抽象机器(1.9)的规则评估e将评估以下表达式之一:
[...]
(2.3)-未定义的constexpr函数或未定义的constexpr构造函数的调用;
由于flag()已声明但未定义,因此它不是常量表达式,违反了14.3.2。

4
根据ISO C++14标准5.19.2规定:
条件表达式e是核心常量表达式,除非e在抽象机器(1.9)的规则下评估时将评估以下表达式之一:
- this (5.1.1),除非在作为e的一部分进行评估的constexpr函数或constexpr构造函数中。 - 对于文字类别的constexpr函数、constexpr函数或微不足道的析构函数(12.4)的隐式调用以外的函数调用[注意:通常应用重载决议(13.3)]; - 一个未定义的constexpr函数或未定义的constexpr构造函数的调用; - (...) Blockquote 在其定义之前进行任何constexpr函数调用的结果都不是常量表达式。
最后似乎这是GCC的错误。

2
我认为每个人都同意这一点。不过还有一些额外的问题,其中最主要的可能是:即使默认模板参数从未被使用,clang是否允许拒绝此程序? - dyp
@FilipRoséen-refp 我知道你在处理Smeta技术时必须处理这个问题,但我不记得这些信息来自哪里。是来自草案、讨论、缺陷报告等吗? - dyp
@dyp 我相当确定我在 http://b.atch.se 的帖子中解释了特定的措辞 - 我目前正在地铁上,但是一旦回到家(希望如此),我可以提供有关此事的详细信息(包括答案)。 - Filip Roséen - refp
@FilipRoséen-refp 我所能找到的只是关于变量模板默认模板参数的措辞(在最近的草案中)。 - dyp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接