【问题标题】:cv-qualifiers and rvalue-referencecv-qualifiers 和 rvalue-reference
【发布时间】:2020-07-25 01:27:18
【问题描述】:

假设我们有如下所示的这段代码,问题是为什么不保留 "c" 的 cv 限定符 (const) 而行为与 "v" 不同?

int main(int argc, char **argv) {
  int x{};
  int y{};
  const auto [v] = std::tuple<int>(x);
  const auto [c] = std::tuple<int&&>(std::move(y));
  decltype(v) vv = 10;  // vv -> const int;
  decltype(c) cc = 100; // cc -> int&&;
  return 0;
}

另外,我可以像下面这样用模板参数推导模拟相同类型的推导过程吗?

template<class T> 
void foo(T t) {  // here should be T rather than universal reference;
  // mimic the same behavior as above somehow ...
}

疑问二:

对于下面的代码,“结构化绑定”的“自动”推断似乎与“自动”的正常用法不一致?

我期望的是,对于第一个“auto”,decltype(v) 应该是 const int 的类型,而不是像第二个那样的 int& 类型,因为我这样做了不要在“auto”旁边指定“&”。那么,“结构化绑定”与“auto”有什么特殊规则吗?

int main(int argc, char **argv) {
  int x{};
  const auto [v] = std::tuple<int&>(x); // v -> int&;
  static_assert(std::is_same_v<decltype(v), int&>);

  int& rx = x;
  const auto c = rx;  // c -> const int;
  static_assert(std::is_same_v<decltype(c), const int>);

  return 0;
}

【问题讨论】:

  • 请注意,应用了const 限定符的int&amp;&amp; 仍然是int&amp;&amp;const 对引用没有意义,因此任何添加它的尝试都无效)。限定符不会“挖掘”过去的参考/指针级别。您可以通过using T = int&amp;&amp;; const T t = 10; 看到这一点
  • @M.M 嗨,为什么 cv-qualifier 作为参考没有任何意义?从c++设计的角度来看,相关的原则是什么?
  • 重新“使用auto 进行结构化绑定”,注意结构化绑定必须始终使用auto

标签: c++ c++17


【解决方案1】:

给定

  const auto [v] = std::tuple<T>(x);

decltype(v) 类型为T const,即const-限定T。如果Tint,那么decltype(v)int const(也可以写成const int)。如果Tint&amp;&amp;,那么decltype(v)int&amp;&amp; const,即int&amp;&amp;(不是const int&amp;&amp;,它是对const int 的引用)。 int&amp;&amp; const 类型与 int&amp;&amp; 相同,因为引用总是有效的 const。它们引用的对象可能是可变的,但 C++ 中的引用本身是不可变的。

据我所知,使用没有通用引用的模板类型推导,您无法模仿这种类型转换(将const 添加到T)。但是有一个类型转换特征std::add_const_t&lt;T&gt;


疑问 2 的更新

结构化绑定

const auto [v] = std::tuple<int&>(x); // v -> int&;

不类似于

int& rx = x;
const auto c = rx;  // c -> const int;

它类似于

const auto e = std::tuple<int&>(x);
auto&& v = std::get<0>(std::move(e));

const 限定符适用于元组,而不是 v 的绑定。引用限定符或缺少它适用于元组。 v 的绑定总是类似于引用。

奇怪的其实是另一种情况:

const auto [v] = std::tuple<int>(x);

仍然 v 类似于引用,但 decltype(v)int。不同之处在于结构化绑定中的绑定是别名,而不是引用。它们是所引用事物的不同名称,但它们本身没有引用类型。

所以:

const auto [v] = std::tuple<T>(x);

最类似于:

const auto e = std::tuple<T>(x);
auto&& r = std::get<0>(std::move(e));
(introduce v as a name for that which r refers to)

第三行不是我们有能力写的。

【讨论】:

  • 我更新了问题并添加了一些关于“auto”与“Structured Binding”的使用的 cmets。你知道这两种使用“auto”的场景有什么区别吗?
【解决方案2】:

正如 Jeff Garret 所提到的,const 将适用于推导出的整个 auto 类型。例如,如果类型为int&amp;,则const auto 将与auto const 相同,与int&amp; const 相同。参考是const,不是数据。

现在,你能做些什么呢?您不必停止使用auto。您可以简单地指定const auto&amp;auto 将推导出为int,整个类型将是const int&amp;(等效于int const&amp;)。这就是你如何让你的数据成为常量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多