繁体   English   中英

左值到右值转换是否应用于非类型左值模板参数?

[英]Does lvalue-to-rvalue conversion is applied to non-type lvalue template argument?

struct S{
   constexpr S() {};
};
template <auto x> void f();

int main() {

    S s{};
    f<s>();
}

首先,根据[temp.arg.nontype]/1

如果模板参数 (13.2) 的类型 T 包含占位符类型 (9.2.9.6) 或推导的 class 类型 (9.2.9.7) 的占位符,则参数的类型是为变量 x 推导的类型发明宣言

T x = template-argument;

如果模板参数声明(13.2)不允许推导参数类型,则程序格式错误。

我们的模板参数包含一个占位符类型auto ,因此参数的类型是为发明声明中的变量x推导出的类型auto x = s; 在这种情况下,参数的类型是S ,并且S是参数声明的允许类型,因为S是结构文字类型。

其次,根据 [temp.arg.nontype]/2

非类型模板参数的模板参数应是模板参数类型的转换常量表达式(7.7)。

这意味着模板参数s应该是一个转换后的常量表达式。 所以根据[expr.const]/10

T T的表达式,其中转换后的表达式是常量表达式,并且隐式转换序列仅包含

  • [..]
  • (10.2) — 左值到右值的转换 (7.3.2)
  • [..]

在应用任何隐式转换之前,我不确定左值s是否被转换为纯右值。 注意 C++14 中转换后的常量表达式的定义是相对变化的。 N4140 §5.19 [expr.const]/3:(强调我的)

T类型的转换常量表达式是一个表达式,隐式转换为T类型的纯右值,其中转换后的表达式是核心常量表达式,并且隐式转换序列仅包含 [..]

因此,根据 C++14,保证转换后的表达式在应用任何隐式转换之前转换为纯右值。

我不太确定左值到右值的转换是否应用于 template-argument s 换句话说,我不确定左值s是否被转换为纯右值。

所以一般来说,如果我将左值作为非类型模板参数的模板参数传递,左值到右值的转换是否应用于该左值?

除此之外,object s常量初始化了吗?

[expr.const]/10 的含义是,每当一个表达式出现在需要“类型T的转换常量表达式”的上下文中时,该表达式就“隐式转换为T类型”以及 [expr.const 中的附加限制]/10 应适用。

所以s没有“在应用任何隐式转换之前转换为纯右值”。 相反, s被隐式转换为类型S ,并且这种隐式转换可能涉及一些标准和/或用户定义的转换,例如左值到右值的转换。 要知道它是否存在,我们必须查看 [conv.general] 中的隐式转换规则。 特别是[conv.general]/6指出

任何隐式转换的效果都与执行相应的声明和初始化,然后使用临时变量作为转换的结果相同。 如果T是左值引用类型或对 function 类型 ([dcl.ref]) 的右值引用,则结果是左值,如果T是对 object 类型的右值引用,则结果是 xvalue,否则是纯右值。 当且仅当初始化使用它作为一个glvalue时,表达式E被用作一个glvalue。

我相信这里的措辞是旧标准版本的遗物。 它应该说的(用现代语言)是,当T是非引用类型时,将E隐式转换为T会产生一个纯右值,它会初始化其结果 object (称为t ),就好像通过T t = E; .

所以我们认为S t = s; 这个初始化有什么作用? 它调用S的复制构造函数来初始化t [dcl.init.general]/16.6.2.1 在这种情况下,没有左值到右值的转换。 (class 类型上的左值到右值转换很少见,但确实发生在语言的某些地方,例如[expr.call]/12[expr.cond]/7 。如果左值到右值转换是在s上执行,它也会调用复制构造函数; [conv.lval]/3.2 。但在这种特殊情况下,语言的规则不需要左值到右值的转换。)

因此,使用s作为S类型模板参数的模板参数的结果是生成了一个纯右值,它通过调用以s作为参数的复制构造函数来初始化其结果 object。 (这个特定的复制构造函数被隐式定义为不做任何事情,因为没有要复制的子对象。)

这回答了您关于是否应用左值到右值转换的问题。 (您可能想知道纯右值实际发生了什么,以及复制构造函数是否实际被调用,但这是一个单独的主题,我现在不想讨论,因为它会使这个答案太长。)

至于s是否是常量初始化的,是的。 它满足 (2.1)(因为它有一个初始化器)和 (2.2),因为它的初始化的完整表达式是一个常量表达式(没有什么可以阻止它成为一个常量表达式,因为它除了调用constexpr什么都不做默认构造函数,它本身什么都不做)。 不过,我不确定这与您的其他问题有什么关系。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM