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

时间:2016-11-14 16:32:32

标签: c++ templates clang language-lawyer constexpr

以下代码使用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查看函数体?

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

1 个答案:

答案 0 :(得分:4)

历史记录:正如评论中所述,此问题已提出为CWG issue 1581。在isocpp.org thread中,Columbo认为代码是有效的,因为模板永远不会在未评估的操作数中实例化,但是on a clang bug report,&#34; rsmith&#34;反驳说,某些decltype表达式确实需要模板实例化。

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

WG21的Richard Smith已于2017年11月开始使用P0859解决此问题。这会向[expr.const]添加新文本,实现clang的行为,如上所述:

  

表达式可能是常量评估如果是:

     
      
  • 潜在评估的表达式([basic.def.odr]),
  •   
  • 一个约束表达式,包括一个由 requires-clause constraint-logical-or-expression 组成的,
  •   
  • braced-init-list的立即子表达式 [脚注:可能需要进行常量评估以确定是否执行缩小转换([dcl.init.list] ])。 ],
  •   
  • 在模板化实体中出现的& cast-expression 形式的表达式[脚注:可能需要进行常量评估以确定是否有这样的表达式是依赖于价值的([temp.dep.constexpr])。 ],或
  •   
  • 上述其中一个的子表达式,它不是嵌套的未评估操作数的子表达式。
  •   

如果是

,则需要进行常量评估

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

并修改[temp.inst]以表示如果模板专门化的定义影响程序的语义,则实例化,这意味着它的需要用于常量评估,如上所述,即使实际上并不需要,可以这么说。

修改ODR以避免Columbo的反对意见。

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

根据这些更改,您的代码decltype(foo(1)),表达式foo(1)不是可能会持续评估(因为它与上面的任何项目符号都不匹配),所以模板不能实例化,并且代码经过修改以避免[dcl.constexpr] / 6,应该成功编译

(C ++ 17 dcl.constexpr / 6表示如果没有有效的专业化,模板是格式错误的NDR; foo也是如此,但这可以通过添加{{1}来解决例如)。