【问题标题】:const decltype(*std::begin(container))& val doesn't make val const?const decltype(*std::begin(container))& val 不使 val const?
【发布时间】:2024-01-19 08:25:01
【问题描述】:

这段代码:

std::vector <int> ints(5,1);
std::for_each(ints.begin(), ints.end(), [](const decltype(*std::begin(ints))& val){ val*=2; });

在 Visual Studio 2010 中编译和运行得很好,并修改容器中的每个值,就像 const 关键字不存在一样。这是编译器中的错误,因为预期的行为是 val 是不可修改的? (换句话说,我希望它不会编译,但它确实)

更新:

std::for_each(ints.begin(), ints.end(), [](const std::remove_reference<decltype(*std::begin(ints))>::type& val){ val*=2; });

似乎行为正确,但这并没有让我更聪明。

注意:

decltype(*std::begin(ints)) 是对 int 的引用。

【问题讨论】:

  • gcc 只是拒绝编译:error: ‘const’ qualifiers cannot be applied to ‘int&amp;’.
  • 它拒绝编译两个版本?
  • 当然,第二个不会编译,因为val是一个常数,不能是*= 2-ed。
  • 啊,是的,愚蠢的我 =) 这就是它应该做的,但第一个在 gcc 中也不能编译?
  • @BenVoigt:是的,如果通过 typedef 或模板参数 (§8.3.2/1) 引入引用,则会忽略 constdecltype 不是其中之一。

标签: c++ visual-c++ lambda constants c++11


【解决方案1】:

似乎编译器试图将const 应用于int&amp;,使其变为int&amp; const,这是多余的,因为无论如何都不能重新定位引用1) .尝试将 const 放在 decltype 和引用之间:decltype(*ints.begin()) const&amp;

1) 感谢 cmets 的澄清。

废话,感谢@Ben 的评论,我注意到了真正的问题。试试decltype(*ints.cbegin())cbegin 返回一个 const_iterator,它取消引用对 const 的引用。此外,不需要额外的 & 符号,因为 *ints.cbegin() 已经返回 int const&amp;

为了解释 OP 的代码出了什么问题,就像 @Ben Voigt 在 cmets 中所说的那样:decltype(*std::begin(ints)) 解析为 int&amp;,因为 std::begin(ints) 返回一个用于非常量容器和取消引用的非常量迭代器这样的迭代器返回一个对非常量的引用。

【讨论】:

  • GCC 应该简单地忽略 const,使结果类型为 int&amp;
  • @Johannes:为什么?我希望代码会给我一个编译错误。
  • const 应用到int&amp; 是完全合法的:ideone.com/aLTJO(Comeau 也接受它)。
  • @Ben:有趣,我会相应地修改我的答案。但是,仅仅因为两个编译器接受它并不意味着它本身是合法的。不过我会相信你和约翰内斯。
  • @Xeo:您​​的修复将无济于事。 declspec 部分解析为 int&amp;,已经是一个参考。