应该decltype(foo(1))实例化constexpr函数模板foo



下面的代码可以在gcc和MSVC下编译,但是在使用clang(我用clang-3.5和当前主干测试)时失败。

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

如果你去掉constexpr,所有的编译器都能很好地编译代码。

问题:
如果声明了返回类型,是否允许decltype查看函数体?

我正在寻找标准中相应部分的参考。

历史记录:如评论所述,此问题作为CWG第1581号问题提出。在isocpp.org线程中,Columbo认为代码是有效的,因为模板永远不会在未求值的操作数中实例化,然而在clang错误报告中,"rsmith"反驳说一些decltype表达式确实需要模板实例化。

clang线程暂时解决了这个问题,提出了自己的(非标准的)标准来确定decltype何时实例化constexpr模板。从4.0版本开始,clang可以成功编译代码。

WG21的Richard Smith在2017年11月开始解决这个问题,P0859。这将向[expr]添加新的文本。Const],它实现了上面讨论的clang的行为:

表达式是潜在的常量,如果它是:

  • 潜在求值表达式([basic.def.odr]),
  • 一个约束表达式,包括由require子句约束逻辑或表达式组成的约束表达式,
  • 带括号的初始化列表的直接子表达式[脚注:常数求值可能需要确定是否执行窄化转换([dcl.init.list])。),
  • 在模板实体中出现的形式为& cast-expression的表达式[脚注:常量计算可能需要确定该表达式是否依赖于值([temp.dep.constexpr])。),或
  • 不是嵌套的未求值操作数的子表达式。

如果满足以下条件,则函数或变量需要用于常量求值

  • 一个constexpr函数,由一个表达式([basic.def.odr])命名,该表达式可能是常量求值,或者
  • 一个变量,其名称显示为一个潜在的常量求值表达式,该表达式要么是constexpr变量,要么是非易失性的const限定整型,要么是引用类型。

和[temp.inst]被修改为,如果一个模板专门化的定义影响了程序的语义,那么它将被实例化,这意味着它是需要用于上面定义的常量求值,即使它实际上并不需要,可以这么说。

修改了ODR以避免colombo的反对。


该提案的建议更改确实出现在N4727中,这是一个后c++ 17草案。所以我认为他们已经被接受了,即使P0859链接和CWG缺陷列表还没有这么说。

在这些更改下,您的代码decltype(foo(1)),表达式foo(1)是不潜在的常数计算(因为它不匹配上面的任何项目符号),所以模板必须不被实例化,并且代码,修改以避免[dcl]。/6, 应该编译成功

(c++ 17 dcl。constexpr/6表示,如果没有有效的专门化,则模板是格式不良的NDR;这对于foo是正确的,但是这可以通过添加template <> constexpr auto wrong<float> = true;(例如)来修复。

相关内容

  • 没有找到相关文章

最新更新