如何最简洁和惯用的方式将数组明确地转换为指针?
例如,考虑需要能够引导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);
foo(x + 0);
foo(+x);
foo(&x[0]); // assuming operator& has not been overloaded for T
foo(std::addressof(x[0])); // since C++11
&*x
,但不是 &x[0]
)具有独特的优势,即数组元素类型不必完整,因此它适用于 struct Foo { static ForwardDeclaredType array[]; };
。 - Johannes Schaub - litb+x
。这是一种方便的方式,可以表示“执行通常的转换和提升”,例如,如果您想将 uint8_t
作为格式化整数而不是原始字节发送到 ostream
。 - Jon Purdyfoo(&x[0]);
从c++11开始,有一种标准方式来表示上述内容:
auto a = std::addressof(x[0]); // a will be * to int
addressof
的签名如下:template<class T> T* addressof(T& arg);
获取对象或函数参数的实际地址,即使存在重载的 & 运算符
另一个想法(也具有上述方法的优点)是编写
auto a = std::begin(x); // a will be * to int
[0]
。std::decay
。+x
。这样更易读吗?更容易理解吗? - dyp&x[0]
更易读,并且可以扩展到适用于任何提供operator[]
方法的类(如果它不提供operator*
,那么&*c
将无法工作。也许在std:vector
或std:array
上?)。如果你说&*c
,我会认为c
是某种迭代器或代理对象,我正在尝试获取实际对象的地址。 - Andre Kostur&*
,因为它产生的是一个迭代器(可能不是指针)。但正如你所争论的那样,有些容器不提供operator*
,有些智能指针也不提供operator[]
。因此,&*p
和&p[0]
具有相同的价值,我个人更喜欢第一个。 - Deduplicator对我来说,股票&x [0]
总是感觉很尴尬,因为相关的数组可以是不完整类型的数组,当然,在这种情况下使用下标运算符是无效的。考虑使用以下方法:
foo(&*x);
这比foo(+x)
多打一个字符,但远不如它易读且难以理解。
[0]
可以用于不完整的数组类型(其元素是完整类型);但不能用于不完整类型的数组。 - M.Mx [0]
以获取地址在概念上是错误的。 - mockinterface&x[0]
和x+0
是否等价的辩论(它们在C中是等价的)对于数组类型;有些人认为如果N
是长度,那么&x[N]
应该是未定义的。 - M.M&x[N]
在某些值的情况下是未定义的,为什么要去那里并开始区分有效和无效的长度,而不是直接使用&*x
并直接使用类型本身的x
。 - mockinterfacex
是重载 &
运算符的类型数组,该怎么办?您可以查看我的答案,其中提供了两种解决方案。 - Nikos Athanasiou&*x
比 &x[0]
更好,原因在我的回答中已经给出。 - mockinterface
template<typename T> void foo(T * const& x);
,从而避免歧义。在对T
进行参数推导时,不再发生数组衰减。 - Johannes Schaub - litbstd::decay
,请查看我的最新更新。 - Nikos Athanasiou