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>返回int,int也需要返回的值来决定是否可以char按预期将其缩小为 a g。这需要使用f来实例化的定义double,这会导致错误。gcc 和 clang 都拒绝此代码。
但是,如果将 的定义g更改为接受int参数:
constexpr void g(int);
Run Code Online (Sandbox Code Playgroud)
那么似乎没有必要实例化 的定义f,因为缩小转换必须成功。事实上,GCC接受这一点,但仍然铿锵实例f与double和拒绝代码。此外,如果f仅声明,但未定义,clang 接受代码,这意味着不需要定义,不应实例化。
我的推理是否正确,这是一个clang错误,还是需要实例化,这实际上是一个gcc错误?
我认为这是CWG #1581 ,由P0859解决。
除非函数模板特化是声明的特化,否则当在需要函数定义存在的上下文中引用该特化时,或者如果定义的存在影响程序的语义,则函数模板特化会被隐式实例化。
存在会影响程序的语义吗?
如果表达式 ([expr.const]) 需要变量或函数进行常量求值,则变量或函数定义的存在被认为会影响程序的语义,即使不需要表达式的常量求值或者如果常量表达式求值不使用定义。
表达式是否需要不断求值?
如果满足以下条件,则需要函数或变量进行持续评估:
- 由可能进行常量计算的表达式命名的 constexpr 函数,或者
- 名称显示为潜在常量计算表达式的变量,该表达式可以是 constexpr 变量,也可以是非易失性 const 限定的整型或引用类型。
它是否由可能常量求值的表达式命名?
如果满足以下条件,则表达式或转换可能被评估为常量:
- 一个明显不断评估的表达式,
- 一个潜在的评估表达式,
- 大括号初始化列表的直接子表达式,
- 模板化实体中出现的 form &cast-expression 的表达式,或者
- 上述任一表达式的子表达式,但不是嵌套未计算操作数的子表达式。
它是花括号初始化列表的直接子表达式。