当不需要检查缩小时,是否需要实例化函数定义?

cig*_*ien 7 c++ language-lawyer narrowing c++20

考虑以下程序:

template<typename T>
constexpr int f() 
{
    T{}.i; // error if instantiated with [T = double]
    return 42;
}

constexpr void g(char);

using U = decltype( g( {f<double>()} ) );
Run Code Online (Sandbox Code Playgroud)

根据我的理解,最后一行是一个错误,因为调用f<double>()是在大括号初始值设定项中,即使f<T>返回intint也需要返回的值来决定是否可以char按预期将其缩小为 a g。这需要使用f来实例化的定义double,这会导致错误。gcc 和 clang 都拒绝此代码。


但是,如果将 的定义g更改为接受int参数:

constexpr void g(int);
Run Code Online (Sandbox Code Playgroud)

那么似乎没有必要实例化 的定义f,因为缩小转换必须成功。事实上,GCC接受这一点,但仍然铿锵实例fdouble和拒绝代码。此外,如果f仅声明,但未定义,clang 接受代码,这意味着不需要定义,不应实例化。

我的推理是否正确,这是一个clang错误,还是需要实例化,这实际上是一个gcc错误?

Jef*_*ett 2

我认为这是CWG #1581 ,由P0859解决。

temp.inst/5说:

除非函数模板特化是声明的特化,否则当在需要函数定义存在的上下文中引用该特化时,或者如果定义的存在影响程序的语义,则函数模板特化会被隐式实例化。

存在会影响程序的语义吗?

temp.inst/8说:

如果表达式 ([expr.const]) 需要变量或函数进行常量求值,则变量或函数定义的存在被认为会影响程序的语义,即使不需要表达式的常量求值或者如果常量表达式求值不使用定义。

表达式是否需要不断求值?

expr.const/15.6-7说:

如果满足以下条件,则需要函数或变量进行持续评估:

  • 由可能进行常量计算的表达式命名的 constexpr 函数,或者
  • 名称显示为潜在常量计算表达式的变量,该表达式可以是 constexpr 变量,也可以是非易失性 const 限定的整型或引用类型。

它是否由可能常量求值的表达式命名?

expr.const/15.1-15.5说:

如果满足以下条件,则表达式或转换可能被评估为常量:

  • 一个明显不断评估的表达式,
  • 一个潜在的评估表达式,
  • 大括号初始化列表的直接子表达式,
  • 模板化实体中出现的 form &cast-expression 的表达式,或者
  • 上述任一表达式的子表达式,但不是嵌套未计算操作数的子表达式。

它是花括号初始化列表的直接子表达式。