Явное расщепление массива на указатель

Каков наиболее лаконичный и идиоматический способ явного преобразования массива в указатель?


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

См. также:  Связанный список: как реализовать деструктор, конструктор копирования и оператор присваивания копирования?
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 3
  1. mockinterface

    Вы можете использовать один из следующих вариантов:

    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[]; }; person mockinterface; 12.04.2014

    Мне больше всего нравится +x. Это удобный способ сказать «выполнить обычные преобразования и рекламные акции», например, если вы хотите отправить uint8_t в ostream в виде форматированного целого числа, а не необработанного байта. person mockinterface; 20.05.2014

  2. mockinterface

    Самый лаконичный и идиоматический? Я бы сказал, взяв адрес первого элемента

    foo(&x[0]);
    

    ОБНОВИТЬ

    Начиная с С++ 11 существует стандартный способ сказать вышесказанное:

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

    adressof имеет следующую подпись

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

    и Получает фактический адрес объекта или функции arg, даже при наличии перегруженного оператора&

    Другая идея (которая также имеет преимущество вышеизложенного) состояла бы в том, чтобы написать

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

    кроме того, это работает с массивами неполных типов, поскольку не требует применения [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

  3. mockinterface

    Стандарт &x[0] всегда казался мне неудобным, потому что рассматриваемый массив может быть массивом неполных типов, и, конечно, нельзя применять к одному из них оператор нижнего индекса. Вместо этого рассмотрите это,

    foo(&*x);
    

    это всего на один символ больше, чем 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

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: