Каков наиболее лаконичный и идиоматический способ явного преобразования массива в указатель?
Например, рассмотрим случай, когда вам нужно иметь возможность направлять 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