【问题标题】:Const and non-const in one variable definition list in C++C++ 中一个变量定义列表中的 const 和 non-const
【发布时间】:2015-03-02 13:53:23
【问题描述】:

为什么不能在一个定义列表中定义 constnon-const 变量?

例如在使用for循环时:

for (size_t i = 0, const iCount = data.size(); i < iCount; ++i);

我猜从 const 正确性的角度来看会更好。

附:我第一次问错了这个问题。它更适合语言设计者,而不是“为什么可以在我的机器上编译?”。我想说的是,如果它在下一个 C++ 标准中作为语法糖来实现会更好。这也将防止在每次循环迭代中调用data.size()。我的意思是,为什么不扩展当前的 C++ 变量定义列表以支持单个定义列表中的 constnon-const

【问题讨论】:

  • 问题不在于const(必然),而是两种不同的类型。
  • @w.b 好吧,我没这么说。我唯一想说的是“好吧,它是不同的类型,但为什么它可以是糖语法,例如在新标准中”?
  • 您的问题是“为什么不可能......”而我的回答是“这是非法的 C++ 语法”。为什么 C++ 标准委员会决定这样做完全是另一个话题。
  • @Cyber​​:问题 const,因为与其他一些修饰符不同,声明语法不允许您将其添加到单个声明符中。不一定禁止两种不同的类型:int i = 0, *p = &amp;i; 是一个完美的声明。

标签: c++ variables standards definition


【解决方案1】:

你不能,因为for 循环声明中只能有一种类型。 const 是类型的一部分。

【讨论】:

  • 这是一个有效的问题,你可以这样做,例如for (int i = 0, *j = &amp;i; ...)ij 有不同的类型。
  • *ji 的类型相同:j 是指向int 类型的指针。的确,这是一个很好的问题,这就是我投赞成票的原因。
【解决方案2】:

在我看来,这只是一个约定。可以采用限定符可以包含在声明符中。

目前您可以将 cv 限定符与指针声明符一起使用。例如这样的构造是有效的

int x, * const p = &x;

所以我看不出这种结构的严重原因

int x, const y = 10;

不允许。

您应该在讨论 C++ 标准的 isocpp.org 上提出这个问题。:)

【讨论】:

  • 谢谢,这是我希望看到的问题。
  • 这个之所以有效是因为 p 的类型是const pointer to int,而不是pointer to const int。因此*p 仍然具有int 类型,因此它通过了编译。
  • @haavee 但是声明并没有声明具有神秘名称 *p 的东西,它声明了名称为 p 的东西。而且p的类型和x的类型不同。
  • 根据标准他们不是。如果你仔细阅读en.cppreference.com/w/cpp/language/declarations 会发现* (pointer-to) 不是 decl-specifier-seq 的一部分。这份文件很难阅读,但它都在那里。
  • @haavee 是的,* 不是 decl-specifier-seq 的一部分,但类型由多个 decl-specifier-seq 控制xp 仍然有不同的类型。 std::is_same&lt;decltype(x), decltype(p)&gt;::valuefalse
【解决方案3】:

我想说的是,如果它在下一个 C++ 标准中作为语法糖来实现会更好。

“语法糖会导致分号癌。”

就规范的复杂性、编译器实现的复杂性、IDE 和代码分析工具的复杂性而言,添加这样的“简单”更改会带来巨大的成本,而且并不一定会使语言更容易教授或使用,除了您展示的一个特定情况。

这也将防止在每次循环迭代中调用 data.size()。

您是否检查过优化代码中是否真的存在多个调用?如果没有,为什么我们需要一个语言扩展来防止一些不会发生的事情?

我的意思是,为什么不扩展当前的 C++ 变量定义列表以支持单个定义列表中的 const 和非 const?

除了for 循环之外,它不会在任何地方广泛使用,而且无论如何你都可以轻松做到:

{
  const size_t iCount = data.size();
  for (size_t i = 0; i < iCount; ++i)
    ;
}

【讨论】:

  • 我同意任何事情,但在最后一个代码 sn-p 中,iCount 变量在我看来有 2 个小坏处:起初它的作用域不仅是 for 循环,而且是整个外部作用域和第二个是它需要一行无用的代码。
  • 额外的大括号使范围相同。有时试图将所有内容都挤在一行上并不能帮助清晰,尤其是在您有多个声明的情况下,当它们具有不同的类型时更是如此。因此,如果该额外的行是无用的,或者实际上使代码更易于阅读,这是值得商榷的。
  • 好吧,我没有注意 sn-p 中的额外花括号 :) 但是,如果我们通常使用 for 循环并定义一个“start”变量,例如 i sn-p 我还希望在它附近看到end 变量定义。也许这只是我,但我在这里看到了一些用处。此外,它不需要 2 个额外的大括号 :) 好的,谢谢您的回答。
【解决方案4】:

for 中,您可以声明多个变量,前提是它们具有相同的类型。 size_tconst size_t 是不同的类型。

你不需要在那里声明iCount,只要写; i &lt; data.size();作为条件。

【讨论】:

  • 然后它将在每次迭代中执行data.size()调用。还是我错了?
  • @VictorPolevoy 如果使用优化编译可能不会。 stackoverflow.com/questions/16945294/…
  • @VictorPolevoy 可能没有,即使有,也有关系吗?
  • 我认为多余的电话总是很重要。在这种情况下 - 也许不是,但要考虑优化。当然,在这种情况下,我们可以在循环之前移动这些计算和分配,但我在这里问的是简单性。就像在 python 中一样。此外,它会花费几行代码:) 我的问题是关于“为什么来实现这个?我认为它会很有用”。
  • @VictorPolevoy 不,它们仅在实际影响性能时才重要。根据我的经验,在 99% 的情况下,您最好编写可读的代码,而不是担心可能会被优化掉的额外调用。至于“为什么”,这是语言设计者的问题。
【解决方案5】:

因为它们是不同的数据类型,因此它不是一个单一的定义列表。

【讨论】:

  • 但是size_t i, *j;声明了两个不同类型的变量。
  • cv 限定符 ('const/volatile) 使它与众不同。可以将*j 解读为“j 是一个变量,当被取消引用时,会产生一种 size_t 类型”。
  • 是的,所以ij是不同类型的变量。
  • 你也可以for (int i=0, j[2] = {0, 1}; ij 再次有不同的类型。
  • 对,所以规则不是你不能有不同的数据类型,因为初始化声明符 D1 和 D2 可以产生不同的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 1970-01-01
  • 2019-02-07
  • 1970-01-01
相关资源
最近更新 更多