将数组显式转换为指针

10

如何最简洁和惯用的方式将数组明确地转换为指针?


例如,考虑需要能够引导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);

5
加一个一元加号可以吗? - dyp
3
你在问什么?上面的代码并不含糊不清。 - juanchopanza
1
@juanchopanza 你试过了吗?我同意这很奇怪,但两者都是完全匹配。 - dyp
3
你可以将第二个模板定义为template<typename T> void foo(T * const& x);,从而避免歧义。在对T进行参数推导时,不再发生数组衰减。 - Johannes Schaub - litb
2
@JohannesSchaub-litb 在C++14中引入了一种最终标准的方法:std::decay,请查看我的最新更新。 - Nikos Athanasiou
显示剩余5条评论
3个回答

9
您可以使用以下其中之一:
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
1
我最喜欢使用 +x。这是一种方便的方式,可以表示“执行通常的转换和提升”,例如,如果您想将 uint8_t 作为格式化整数而不是原始字节发送到 ostream - Jon Purdy

5
我认为最简洁和惯用的做法是获取第一个元素的地址。
foo(&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]
更新2
自c++ 14以来,甚至有更明确的功能:std::decay

@Deduplicator,那么您也可以使用+x。这样更易读吗?更容易理解吗? - dyp
@dyp:这个问题需要“简洁和惯用语”。它并不会变得不可读、更难理解或者不够惯用。尽管如此,它的改进并不大(虽然它具有更高的绑定能力)。比一元加号不够简洁。 - Deduplicator
1
@Deduplicator 对于一个数组,我认为&x[0]更易读,并且可以扩展到适用于任何提供operator[]方法的类(如果它不提供operator*,那么&*c将无法工作。也许在std:vectorstd:array上?)。如果你说&*c,我会认为c是某种迭代器或代理对象,我正在尝试获取实际对象的地址。 - Andre Kostur
看起来很不错,只是对于最后一个(std::begin),你仍然需要添加&*,因为它产生的是一个迭代器(可能不是指针)。但正如你所争论的那样,有些容器不提供operator*,有些智能指针也不提供operator[]。因此,&*p&p[0]具有相同的价值,我个人更喜欢第一个。 - Deduplicator

2

对我来说,股票&x [0]总是感觉很尴尬,因为相关的数组可以是不完整类型的数组,当然,在这种情况下使用下标运算符是无效的。考虑使用以下方法:

foo(&*x);

这比foo(+x)多打一个字符,但远不如它易读且难以理解。


1
澄清一下,[0] 可以用于不完整的数组类型(其元素是完整类型);但不能用于不完整类型的数组。 - M.M
此外,如果使用零数组长度扩展进行工作,则遍历x [0]以获取地址在概念上是错误的。 - mockinterface
在C++中我看到了长时间的关于&x[0]x+0是否等价的辩论(它们在C中是等价的)对于数组类型;有些人认为如果N是长度,那么&x[N]应该是未定义的。 - M.M
@MattMcNabb同意,如果有人认为&x[N]在某些值的情况下是未定义的,为什么要去那里并开始区分有效和无效的长度,而不是直接使用&*x并直接使用类型本身的x - mockinterface
@mockinterface 如果 x 是重载 & 运算符的类型数组,该怎么办?您可以查看我的答案,其中提供了两种解决方案。 - Nikos Athanasiou
@NikosAthanasiou 感谢您的努力,但我认为您自相矛盾 - 您的真正答案使用 '&',因此它也面临重载问题(重载取地址符是非常牵强附会和非常罕见的),虽然我感激您提到了标准方法 - 它们不够简洁,而我认为 &*x&x[0] 更好,原因在我的回答中已经给出。 - mockinterface

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接