list vs aggregate initialization
От: rg45 СССР  
Дата: 01.03.18 19:45
Оценка:
Привет всем. Есть желание поговорить об aggregate и list инициализацииях и о том, как их подружить.

Дана структура, которая выглядит примерно так:

template <typename T, size_t N>
struct Array
{
   T data[N];
};


ну или так (в контескте данного топика эти определения полностью равнозначны):

template <typename T, size_t N>
struct Array
{
   std::array<T,N> data;
};


Эта структура поддерживает агрегатную инициализацию и может быть проинициализирована, например, вот так:

Array<int, 10> array { 0, 1, 2, 3, 4, /* 5, 6, 7, 8, 9 */ }; // Обратите внимание на возможность неполной спецификации


Этот тип позволяет создавать вложенные структуры данных и по-прежнему поддерживает агрегатную инициализацию, например:

Array<Array<Array<int, 3>, 3>, 3> table { 0, 1, 2, /*....*/};


Теперь задача в том, чтобы сделать член data закрытым и предоставить конструкторы для этого класса так, чтобы форма инициализации не изменилась. Ну или изменилась, но как-нибудь разумно. Например, меня бы устроило, если бы инициализация вложенных структур данных выглядела бы так:

Array<Array<int, 3>, 3> table { { 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 }};


Но это уже опционально — если сохранится вид, присущий агрегатной инициализации, меня бы это вполне устроило.

Короче говоря, вот в этом примере: https://ideone.com/SxpvxR нужно сделать член data закрытым.

  Чего НЕ хотелость бы получить
так это необходимость указывать типы элементов явно:
Array<Array<int, 3>, 3> table { Array<int, 3>{ 11, 12, 13 }, Array<int, 3>{ 21, 22, 23 }, Array<int, 3>{ 31, 32, 33 }};
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 01.03.2018 20:17 rg45 . Предыдущая версия . Еще …
Отредактировано 01.03.2018 20:15 rg45 . Предыдущая версия .
Re: list vs aggregate initialization
От: watchmaker  
Дата: 01.03.18 20:49
Оценка: 25 (3)
Здравствуйте, rg45, Вы писали:

R>Привет всем. Есть желание поговорить об aggregate и list инициализацииях и о том, как их подружить.


В общем-то теперь, когда в constexpr-функциях можно практически себя не ограничивать, то можно тупо в лоб расписать любую логику инициализации.
Например:
template <typename T, size_t N>
struct Array
{
private:
    T data[N];
public:
    constexpr Array(std::initializer_list<T> init)
        : data{}
    {  
        if (init.size() > N) {
            throw "overflow";
        }
        using std::begin;
        using std::end;
        auto dst = begin(data);
        for (auto src = begin(init); src != end(init); ++src, ++dst) {
            *dst = *src;
        }
    }

    auto begin() const { return std::begin(data); }
    auto end() const { return std::end(data); }
};


Вполне работает.
И если пометить результат как constexpr, то все эти циклы и проверки гарантированно будут выполняются на этапе компиляции: https://ideone.com/J3t69X
Re[2]: list vs aggregate initialization
От: rg45 СССР  
Дата: 01.03.18 20:52
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Вполне работает.

W>И если пометить результат как constexpr, то все эти циклы и проверки гарантированно будут выполняются на этапе компиляции: https://ideone.com/J3t69X

Я забыл акцент проставить, вообще-то, мечта была все это проделать в списке инициализации. И у меня даже есть рабочий вариант, но он ужасен!

Список инициализации ведь совсем не обязательно состоит из констант, там вполне могут быть и рантаймовые данные. Да и сами объекты Array, если смотреть с прицелом в прикладную область, не будут constexpr, в большинстве своем.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 01.03.2018 21:30 rg45 . Предыдущая версия . Еще …
Отредактировано 01.03.2018 21:27 rg45 . Предыдущая версия .
Отредактировано 01.03.2018 20:53 rg45 . Предыдущая версия .
Re[2]: list vs aggregate initialization
От: rg45 СССР  
Дата: 01.03.18 20:59
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>В общем-то теперь, когда в constexpr-функциях можно практически себя не ограничивать, то можно тупо в лоб расписать любую логику инициализации.

W>Например:
W>
W>    constexpr Array(std::initializer_list<T> init)
W>


Кстати, может прокомментируешь, почему рекоммендуют initializer_list принимать по значению? Это что-то меняет принципиально?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: list vs aggregate initialization
От: reversecode google
Дата: 01.03.18 21:13
Оценка: 23 (2)
https://stackoverflow.com/questions/17803475/why-is-stdinitializer-list-often-passed-by-value

насколько я понимаю аналогично string_view
Re[4]: list vs aggregate initialization
От: rg45 СССР  
Дата: 01.03.18 21:19
Оценка:
Здравствуйте, reversecode, Вы писали:

R>https://stackoverflow.com/questions/17803475/why-is-stdinitializer-list-often-passed-by-value


R>насколько я понимаю аналогично string_view


Ну доводы понятны, в принципе. В то же время, никто не говорит: "не передавайте по ссылке, а то случится что-нибудь страшное" Меня вот этот момент интересовал больше всего.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: list vs aggregate initialization
От: reversecode google
Дата: 01.03.18 21:30
Оценка: :)
как это не случится ? случится, код медленнее будет)) лишних операторов копирования добавится
и потом герои будут по форумам кричать что С++ тормозит итд
Re[6]: list vs aggregate initialization
От: rg45 СССР  
Дата: 01.03.18 21:41
Оценка:
Здравствуйте, reversecode, Вы писали:


R>как это не случится ? случится, код медленнее будет)) лишних операторов копирования добавится

R>и потом герои будут по форумам кричать что С++ тормозит итд

Я сегодня, совершенно случайно, заглянул в холивары, оказывается, вопрос ненужности плюсов уже давно решён
Автор: IT
Дата: 26.02.18
. Человечеством
Автор: IT
Дата: 26.02.18
.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: list vs aggregate initialization
От: rg45 СССР  
Дата: 01.03.18 23:22
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>В общем-то теперь, когда в constexpr-функциях можно практически себя не ограничивать, то можно тупо в лоб расписать любую логику инициализации.

W>И если пометить результат как constexpr, то все эти циклы и проверки гарантированно будут выполняются на этапе компиляции: https://ideone.com/J3t69X

Я пока рассматриваю только сценарий, когда все эти объекты НЕ constexpr. Дошел вот до такого извращения:

https://ideone.com/3vSCbr

template <typename T, size_t N>
struct Array
{
public:

   Array() = default;
   Array(std::initializer_list<T> init) : Array(init, std::make_index_sequence<N>()) {}

   auto begin() const { return std::begin(data); }
   auto end() const { return std::end(data); }

private:
   template <size_t...I>
   Array(std::initializer_list<T> init, std::index_sequence<I...>, T def_value = T())
      : data {get<I>(init, def_value)...} { }

   template <size_t I>
   static const T& get(const std::initializer_list<T>& init, const T& def_value) {
      return I < init.size() ? init.begin()[I] : def_value;
   }

private:
   std::array<T,N> data;
   // T data[N];
};


Смотрю на него и думаю, стоит ли копья ломать? А может, идея какая придет в голову кому-нибудь.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 01.03.2018 23:28 rg45 . Предыдущая версия .
Re[3]: list vs aggregate initialization
От: reversecode google
Дата: 01.03.18 23:31
Оценка:
если боятся Array<Array<Array<Array<int, 3>, 3>, 3>, 3> итд то наверное стоит
Re[4]: list vs aggregate initialization
От: rg45 СССР  
Дата: 01.03.18 23:35
Оценка:
Здравствуйте, reversecode, Вы писали:


R>если боятся Array<Array<Array<Array<int, 3>, 3>, 3>, 3> итд то наверное стоит


Самое паршивое здесь — это обработка несовпадающих размеров. Если б не это, то было бы вполне шоколадно.
--
Не можешь достичь желаемого — пожелай достигнутого.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.