Каков наиболее лаконичный и идиоматический способ явного преобразования массива в указатель?
Например, рассмотрим случай, когда вам нужно иметь возможность направлять 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);
Может быть, с унарным плюсом? — person mockinterface schedule 11.04.2014
Что ты спрашиваешь? Приведенный выше код не является двусмысленным. — person mockinterface schedule 11.04.2014
@juanchopanza Ты пробовал? Я согласен, что это странно, но оба являются точными совпадениями. — person mockinterface schedule 11.04.2014
@dyp Я пробовал. Первый вариант лучше подходит. Или мой компилятор (gcc 4.7.3) не работает? — person mockinterface schedule 11.04.2014
Clang++ и g++ coliru говорят, что это неоднозначно: coliru.stacked-crooked.com/a/078c26aeb1abb226</ а> — person mockinterface schedule 11.04.2014
Да, они неоднозначны. Я так и не удосужился изучить это подробнее,
здесь — person mockinterface schedule 11.04.2014
Другим вариантом был бы явный выбор шаблона… — person mockinterface schedule 11.04.2014
Вы можете избежать двусмысленности, определив второй шаблон как template<typename T> void foo(T * const& x);
. При выводе аргумента для T
больше не будет распада массива. — person mockinterface schedule 12.04.2014
@JohannesSchaub-litb В C++14 был введен окончательный стандартный способ: std::decay
, см. мое последнее обновление — person mockinterface schedule 20.05.2014
Связано: Какова цель унарного оператора плюс? и что такое затухание массива?. — person mockinterface schedule 25.03.2015
Вы можете использовать один из следующих вариантов:
Центральный (как и
&*x
, но не&x[0]
) имеет уникальное преимущество в том, что тип элемента массива не обязательно должен быть полным, поэтому он работает наstruct Foo { static ForwardDeclaredType array[]; };
— person mockinterface; 12.04.2014Мне больше всего нравится
+x
. Это удобный способ сказать «выполнить обычные преобразования и рекламные акции», например, если вы хотите отправитьuint8_t
вostream
в виде форматированного целого числа, а не необработанного байта. — person mockinterface; 20.05.2014Самый лаконичный и идиоматический? Я бы сказал, взяв адрес первого элемента
ОБНОВИТЬ
Начиная с С++ 11 существует стандартный способ сказать вышесказанное:
adressof
имеет следующую подписьи Получает фактический адрес объекта или функции arg, даже при наличии перегруженного оператора&
Другая идея (которая также имеет преимущество вышеизложенного) состояла бы в том, чтобы написать
кроме того, это работает с массивами неполных типов, поскольку не требует применения
[0]
ОБНОВЛЕНИЕ 2
Начиная с C++ 14, в этом есть еще более явная функциональность:
std::decay
</ а>@Deduplicator Тогда вы также можете использовать
+x
. Это более читабельно? Легче понять? — person mockinterface; 11.04.2014@dyp: Вопрос нужен
concise and idiomatic
. Он не менее удобочитаем, труден для понимания и менее идиоматичен. Тем не менее, ненамного лучше, чем +0 (хотя сила связывания у него выше). Менее краткий, чем унарный плюс… — person mockinterface; 11.04.2014@Deduplicator Для массива я думаю, что
&x[0]
легче читать, и его можно расширить для применения к любому классу, который предоставляет методoperator[]
(и если он не предоставляетoperator*
, то&*c
не будет работать. Возможно, наstd:vector
, илиstd:array
?). Если вы говорите&*c
, я думаю, чтоc
— это какой-то итератор или какой-то прокси-объект, и я пытаюсь получить адрес фактического объекта. — person mockinterface; 11.04.2014Выглядит довольно хорошо, только для последнего (std::begin) вам все равно нужно добавить
&*
, потому что он дает итератор (который не обязательно должен быть указателем). Но так же, как вы утверждаете, что есть некоторые контейнеры, не предоставляющиеoperator*
, есть некоторые умные указатели, не предоставляющиеoperator[]
. Итак,&*p
и&p[0]
равноценны, лично я предпочитаю первое. — person mockinterface; 27.04.2014Стандарт
&x[0]
всегда казался мне неудобным, потому что рассматриваемый массив может быть массивом неполных типов, и, конечно, нельзя применять к одному из них оператор нижнего индекса. Вместо этого рассмотрите это,это всего на один символ больше, чем
foo(+x)
, который гораздо менее удобочитаем и труден для понимания.Чтобы уточнить,
[0]
можно использовать для неполного типа массива (элементы которого являются полными типами); но не в массиве неполных типов. — person mockinterface; 12.04.2014Кроме того, если кто-то работает с нулевой длиной массива extensions, обход
x[0]
для получения адреса теоретически неверен. — person mockinterface; 12.04.2014Я видел долгие дебаты о том, эквивалентны ли
&x[0]
иx+0
в C++ (они есть в C) для типов массивов; некоторые считают, что&x[N]
должно быть неопределенным, еслиN
— это длина. — person mockinterface; 12.04.2014@MattMcNabb Согласитесь, если кто-то утверждает, что
&x[N]
не определено для некоторых значенийN
, зачем вообще туда идти и начинать различать допустимые и недопустимые длины вместо того, чтобы просто выполнять&*x
работу сx
самим типом напрямую. — person mockinterface; 12.04.2014@mockinterface Что, если
x
— это массив типов, которые перегружают оператор&
? Вы можете проверить мой ответ для двух решений на этом — person mockinterface; 27.04.2014@NikosAthanasiou Спасибо за ваши усилия, Никос, но я думаю, вы скорее противоречите сами себе — в вашем реальном ответе используется «&», поэтому он подвержен той же проблеме перегрузки (а перегрузка address-of довольно надуманная и очень редкая), и в то время как я ценю, что вы упомянули стандартные способы — они не краткие, и я думаю, что
&*x
лучше, чем&x[0]
по причинам, которые я указал в своем ответе. — person mockinterface; 28.04.2014