【问题标题】:Explicit decay of an array into a pointer将数组显式衰减为指针
【发布时间】:2014-04-11 12:05:06
【问题描述】:

显式将数组衰减为指针的最简洁和惯用的方法是什么?


例如,考虑您需要能够指导 SFINAE 或明确说明过载的情况:

template<typename T, std::size_t N> void foo(T(&x)[N]);
template<typename T>                void foo(T *x); 
//
int x[2] = {0, 1};
foo(x);

【问题讨论】:

  • 可能是一元加号?
  • 你在问什么?上面的代码没有歧义。
  • @juanchopanza 你试过了吗?我同意这很奇怪,但两者都是完全匹配。
  • 您可以通过将第二个模板定义为template&lt;typename T&gt; void foo(T * const&amp; x); 来避免歧义。在T 的参数推导过程中不会再发生数组衰减。
  • @JohannesSchaub-litb 在 C++14 中引入了最终的标准方式:std::decay,请参阅我的最新更新

标签: c++ arrays pointers c++11


【解决方案1】:

您可以使用以下方法之一:

foo(x + 0);
foo(+x);
foo(&x[0]); // assuming operator& has not been overloaded for T
foo(std::addressof(x[0])); // since C++11

【讨论】:

  • 中间那个(和&amp;*x一样,但不是&amp;x[0])具有独特的优势,数组元素类型不必是完整的,所以它适用于struct Foo { static ForwardDeclaredType array[]; };跨度>
  • 我最喜欢+x。这是说“进行通常的转换和促销”的便捷方式,例如,如果您想将 uint8_t 作为格式化整数而不是原始字节发送到 ostream
【解决方案2】:

最简洁和惯用的?我会说取第一个元素的地址

foo(&x[0]);

更新

从 c++11 开始,有一个 standard way 表示上述内容:

auto a = std::addressof(x[0]); // a will be * to int

adressof 具有以下签名

template<class T> T* addressof(T& arg);

and 获取对象或函数 arg 的实际地址,即使存在重载运算符&

另一个想法(也具有上述优点)是写

auto a = std::begin(x); // a will be * to int

此外,这适用于不完整类型的数组,因为它不需要应用 [0]

更新 2

自 c++ 14 起有更明确的功能:std::decay

【讨论】:

  • @Deduplicator 然后你也可以使用+x。是不是更具可读性?更容易理解?
  • @dyp:想要的问题concise and idiomatic。它的可读性、更难理解或惯用语并不逊色。尽管如此,并不比 +0 好多少(尽管它具有更强的绑定能力)。不如一元加号简洁...
  • @Deduplicator 对于我认为&amp;x[0] 更易于阅读的数组,可以扩展以应用于任何提供operator[] 方法的类(如果它不提供@987654334 @,然后&amp;*c 将不起作用。也许在std:vectorstd:array?)。如果你说&amp;*c,我认为c 是某种迭代器或某种代理对象,我正在尝试获取实际对象的地址。
  • 它看起来很不错,只是对于最后一个(std::begin)你仍然需要添加&amp;*,因为它产生了一个迭代器(它不需要是一个指针)。但正如您认为有些容器不提供operator* 一样,有些智能指针不提供operator[]。所以,&amp;*p&amp;p[0] 是同等价值的,我个人更喜欢第一个。
【解决方案3】:

股票&amp;x[0] 总是让我觉得很尴尬,因为有问题的数组可能是一个不完整类型的数组,当然对一个数组应用下标运算符是无效的。考虑一下,

foo(&*x);

这仅比foo(+x) 多一个字符,后者可读性差,更难理解。

【讨论】:

  • 澄清一下,[0] 可用于不完整的数组类型(其元素是完整类型);但不是在不完整类型的数组上。
  • 另外,如果使用零数组长度extensions,遍历x[0]获取地址在理论上是错误的。
  • 我已经看到了关于 &amp;x[0]x+0 在 C++ 中(它们在 C 中)对于数组类型是否等效的长期争论;有些人认为如果N 是长度,则&amp;x[N] 应该是未定义的。
  • @MattMcNabb 同意,如果有人认为 &amp;x[N] 对于 N 的某些值是未定义的,为什么还要去那里并开始区分有效和无效长度,而不是仅仅做 &amp;*x直接使用 x 类型本身。
  • @mockinterface 如果x 是一个重载&amp; 运算符的类型数组怎么办?您可以查看我对此的两个解决方案的答案
猜你喜欢
  • 2011-11-14
  • 2013-07-19
  • 1970-01-01
  • 2021-12-01
  • 2021-05-06
相关资源
最近更新 更多