问题描述
以下代码可与gcc和MSVC一起编译,但无法使用我在clang-3.5和当前中继上测试过的clang.
The following code compiles with with gcc and MSVC, but fails using clang I tested with clang-3.5 and current trunk).
template <typename T>
constexpr auto wrong = false;
template <typename T>
constexpr auto foo(const T t) -> int
{
static_assert(wrong<T>, "");
return {};
}
using F = decltype(foo(1));
int main() {}
clang实例化函数主体并偶然发现 static_assert
.gcc和MSVC仅查看函数声明,而忽略正文中的 static_assert
.
clang instantiates the function body and stumbles over the static_assert
. gcc and MSVC just look at the function declaration and ignore the static_assert
in the body.
如果删除constexpr,则所有编译器都可以正常编译代码.
If you remove the constexpr, all compilers compile the code just fine.
问题:
如果声明了返回类型,是否允许decltype查看函数体?
Question:
Is decltype allowed to look into the function body if the return type is declared?
我正在寻找对标准中各个部分的引用.
I am looking for a reference to the respective section in the standard.
推荐答案
历史:如评论中所述,此问题被提出为 CWG问题1581 .在 isocpp.org线程中,哥伦布认为该代码之所以有效,是因为模板从未在未评估的操作数之内实例化,但是在clang错误报告中 ,"rsmith"反驳说,某些 decltype
表达式确实确实需要模板实例化.
History: As noted in comments, this issue was raised as CWG issue 1581. In a isocpp.org thread, Columbo argued that the code was valid because templates are never instantiated inside unevaluated operands, however on a clang bug report, "rsmith" countered that some decltype
expressions definitely did require template instantiation.
clang线程通过提出自己的(非标准)标准来临时解决此问题,以使 decltype
何时实例化 constexpr
模板.从4.0版开始,clang会成功编译代码.
The clang thread temporarily resolved the issue by coming up with their own (non-standard) criteria for when decltype
would instantiate a constexpr
template. Since version 4.0, clang does compile the code successfully.
WG21的理查德·史密斯(Richard Smith)于2017年11月开始使用 P0859 解决此问题.这会将新文本添加到[expr.const]中,该文本实现了如上所述的clang行为:
Richard Smith of WG21 has started to address the issue as of November 2017, with P0859. This adds new text to [expr.const] which implement the behaviour of clang as discussed above:
- 可能评估的表达式([basic.def.odr])
- 一个约束表达式,包括一个由需求子句的逻辑约束或表达式形成的,
- 括号初始列表 [脚注:的立即子表达式:可能需要进行常量评估以确定是否执行了变窄转换([dcl.init.list]).],
- 以模板实体形式出现的
&
cast-expression 形式的表达式[这样的表达式是否取决于值([temp.dep.constexpr]).]或 - 上述之一的子表达式,不是嵌套的未评估操作数的子表达式.
- a potentially-evaluated expression ([basic.def.odr]),
- a constraint-expression, including one formed from the constraint-logical-or-expression of a requires-clause,
- an immediate subexpression of a braced-init-list[ Footnote: Constant evaluation may be necessary to determine whether a narrowing conversion is performed ([dcl.init.list]). ],
- an expression of the form
&
cast-expression that occurs within a templated entity[ Footnote: Constant evaluation may be necessary to determine whether such an expression is value-dependent ([temp.dep.constexpr]). ], or - a subexpression of one of the above that is not a subexpression of a nested unevaluated operand.
需要常量或常量的函数 :
[temp.inst]被修改为,如果模板专用化的定义会影响程序的语义,则实例化模板专用化 ,这意味着它需要进行持续评估 >如上所述,即使实际上并不需要,也可以.
And [temp.inst] is modified to say that a template specialization is instantiated if its definition affects the semantics of the program, which means that it's needed for constant evaluation as defined above, even if it isn't actually needed, so to speak.
修改了ODR以避免Columbo的反对.
The ODR is modified to avoid Columbo's objection.
有关该建议的建议更改的确出现在N4727中,这是C ++ 17之后的草案.因此,即使P0859链接和CWG缺陷列表尚未声明,我都认为它们已被接受.
The recommended changes on that proposal do appear in N4727, which is a post-C++17 draft. So I assume they have been accepted even though the P0859 link and the CWG defect list don't say so yet.
在这些更改下,您的代码 decltype(foo(1))
,表达式 foo(1)
不是可能常量求值的((因为它与上面的任何要点都不匹配),因此不得实例化该模板,并且对代码进行修改以避免[dcl.constexpr]/6,应成功编译.
Under these changes, your code decltype(foo(1))
, the expression foo(1)
is NOT potentially constant evaluated (because it does not match any of the bullet points above), so the template must not be instantiated, and the code, with a modification to avoid [dcl.constexpr]/6, should compile successfully.
(C ++ 17 dcl.constexpr/6表示如果没有有效的专业化,则模板是格式错误的NDR;这对于 foo
是正确的,但是可以通过添加模板<> constexpr自动错误< float> = true; ).
(C++17 dcl.constexpr/6 says that a template is ill-formed NDR if there are no valid specializations; which is true for foo
, however this can be fixed by adding template <> constexpr auto wrong<float> = true;
for example).
这篇关于应该decltype(foo(1))实例化constexpr函数模板foo吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!