【问题标题】:Why does the vc++ 2019 not accept the code?为什么vc++ 2019不接受代码?
【发布时间】:2019-12-08 15:42:44
【问题描述】:
template<int N>
void f()
{
    constexpr int n = 9;
    ++*const_cast<int*>(&n); // ok
    ++*const_cast<int*>(&N); // error C2101: '&' on constant
}

int main()
{
    f<8>();
}

根据cppref

变量、函数、模板参数对象的名称(因为 C++20) 或数据成员,无论类型如何,例如 std::cin 或 标准::endl。即使变量的类型是右值引用, 由其名称组成的表达式是左值表达式;

两个问题:

1.为什么vc++ 2019 (with /std:c++latest) 不接受代码?

2。为什么 C++20 允许模板参数对象是左值?

【问题讨论】:

  • 它到底应该取什么地址? N 不是变量。
  • 即使你可以说服你的编译器采用那个地址(我不知道它是否有意义),增加一个const 值会触发 UB。
  • 另外,如果你想要一个标准的答案,我建议使用language-lawyer 标签。
  • 也许++*const_cast&lt;int*&gt; 部分可以为了最小的例子而省略?还是应该在这里相关?
  • 同样来自cppreference: 当一个非类型模板参数的名字用在类模板主体内的表达式中时,它是一个不可修改的纯右值,除非它的类型是左值引用类型,或者除非它的类型是类类型(C++20 起)。。你不能取prvalue的地址。

标签: c++ constants language-lawyer constexpr c++20


【解决方案1】:

模板参数对象是一个规范术语,仅指具有类类型的模板参数。

temp.param/6(强调我的)

...一个 id 表达式 命名类类型 T 的非类型模板参数 表示类型为 const T 的静态存储持续时间对象,称为 模板参数对象,其值为对应的 模板参数转换为 模板参数。程序中的所有此类模板参数 相同的类型和相同的值表示相同的模板参数 目的。 [ 注意:如果一个 id 表达式命名一个非类型非引用 模板参数,则如果它具有非类类型,则它是纯右值。 否则,如果它是类类型 T,它是一个左值并且具有类型 const T ([expr.prim.id.unqual])。 — 尾注 ]

由于int 不是类类型,它不是模板参数对象。我们可以在此处查阅有关值类别的规范性文本的相关部分,支持注释:

expr.prim.id.unqual/2

... 如果实体是函数、变量、 结构化绑定 ([dcl.struct.bind])、数据成员或模板 参数对象和prvalue,否则...

由于我们不在“模板参数对象”的情况下,我们正在处理一个纯右值,因此可能不会像任何其他纯右值一样将一元 &amp; 应用于它。

【讨论】:

    【解决方案2】:

    模板参数在编译时被相应的值替换。所以 N 不是变量,而是更像一个宏。在您的示例中,您调用 f() 所以行 ++*const_cast&lt;int*&gt;(&amp;N); 将变为 ++*const_cast&lt;int*&gt;(&amp;8);

    当然你不能取8的地址。

    【讨论】:

    • 这显然是编译器实现它的方式,但与 OP 引用的文档不一致。
    猜你喜欢
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 2017-01-10
    • 1970-01-01
    • 2020-10-14
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多