initializer_list и неизвестная размерность
От: Bill Baklushi СССР  
Дата: 23.11.20 17:01
Оценка:
Приветствую.

По мотивам моего велосипеда https://rsdn.org/forum/cpp.applied/7854228.all
Автор: Свободу rg45!
Дата: 15.10.20


Там я применил инициализцию двумя параметрами-initializer_list — размерности и собственно данных.

Хочется инициализировать массив одним initializer_list, но рекурсивным. Например
multidim_dynarray arr{ {{ 1, 3 }, {2, 5 }},  {{ 4, 7 }, {6, 8 }} };

Тут синтаксис подкладывает свинью.

Вот это работает:
#include <iostream>
#include <initializer_list>

int main()
{
    auto v = { 1, 2, 3 };
    std::cout << typeid(v).name() << std::endl;
    return 0;
}

А если
auto v={ { 1, 3 }, {2} };

то уже не компилируется. Тип v автоматом не выводится, его нужно прописать явно
std::initializer_list<std::initializer_list<int>> v = { { 1, 3 }, {2} };


Это не страшно, но рекурсивный initializer_list тоже не работает.

Вот пример, для начала вычисляющий число измерений.
int func(int t)
{
    return 0;    
}

template <typename T> int func(std::initializer_list<T> t)
{
    return 1+func(*std::begin(t));
}


Обычный код не собирается
std::cout << func({ { 1, 3 }, {2} }) << std::endl;


Нужно
std::cout << func(std::initializer_list<std::initializer_list<int>> { { 1, 3 }, {2} }) << std::endl;

что неудобно.

Что-то можно сделать или в морг?

PS. Вроде видел какое-то решение на гитхабах, но найти не могу...
Модератор-националист Kerk преследует оппонентов по политическим мотивам.
Re: initializer_list и неизвестная размерность
От: rg45 СССР  
Дата: 24.11.20 11:49
Оценка: 43 (7)
Здравствуйте, Bill Baklushi, Вы писали:

BB>Хочется инициализировать массив одним initializer_list, но рекурсивным. Например

BB>Что-то можно сделать или в морг?

Ну вот такой эскиз подхода, возможно, окажется полезным:

http://coliru.stacked-crooked.com/a/5bd94a0085515e8e

#include <vector>

struct Tree : std::vector<Tree>
{
    int val {};
    Tree(int val = 0) : val(val) {}
    Tree(std::initializer_list<Tree> children) : vector(children) {}
};

int main()
{
    Tree tree { 1, {2, 3, {4, 5, {11, 12, 13}, 6}, {7, 8, 9}}};
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 24.11.2020 11:53 rg45 . Предыдущая версия .
Re[2]: initializer_list и неизвестная размерность
От: ArtDenis Россия  
Дата: 25.11.20 14:17
Оценка:
Здравствуйте, rg45, Вы писали:

R>http://coliru.stacked-crooked.com/a/5bd94a0085515e8e


Тут по смыслу вроде как std::variant нужон:
struct Tree
{
    using Vct = std::vector<Tree>;

    std::variant<Vct, int> val;
    
    Tree(int val) : val(val) {}
    Tree(std::initializer_list<Tree> children) : val(children) {}
};

Но это уже чисто придирки )
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: initializer_list и неизвестная размерность
От: Bill Baklushi СССР  
Дата: 25.11.20 14:52
Оценка:
ArtDenis:

R>>http://coliru.stacked-crooked.com/a/5bd94a0085515e8e


AD>Тут по смыслу вроде как std::variant нужон:

AD>
AD>struct Tree
AD>{
AD>    using Vct = std::vector<Tree>;

AD>    std::variant<Vct, int> val;
    
AD>    Tree(int val) : val(val) {}
AD>    Tree(std::initializer_list<Tree> children) : val(children) {}
AD>};
AD>

AD>Но это уже чисто придирки )

Если придирки пошли, то можно сделать каждую фигурную скобку однородной:
#include <initializer_list>
#include <vector>
#include <variant>

struct Tree
{
    std::variant<std::vector<Tree>, std::vector<int>> val_;
    Tree(std::initializer_list<int> children) : val_(children) {}
    Tree(std::initializer_list<Tree> children) : val_(children) {}
};

int main()
{
    //Tree tree { 1, {2, 3, {4, 5, {11, 12, 13}, 6}, {7, 8, 9}}}; // ERROR
    Tree tree { {{ 1, 3 }, {2, 5 }},  {{ 4, 7 }, {6, 8 }} };  // OK
}
Модератор-националист Kerk преследует оппонентов по политическим мотивам.
Re[4]: initializer_list и неизвестная размерность
От: ArtDenis Россия  
Дата: 25.11.20 15:08
Оценка:
Здравствуйте, Bill Baklushi, Вы писали:

BB>...


Если уж придирки продолжились и с учётом того, что скорее всего Tree будет использоваться только при инициализации (как тип аргумента функции инициализации), то можно уменьшить потребление памяти и количество алокаций:

struct Tree
{
    std::variant<std::vector<Tree>, std::initializer_list<int>> val_;
    Tree(std::initializer_list<int> children) : val_(children) {}
    Tree(std::initializer_list<Tree> children) : val_(children) {}
};
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Отредактировано 25.11.2020 15:10 ArtDenis . Предыдущая версия .
Re[5]: initializer_list и неизвестная размерность
От: Bill Baklushi СССР  
Дата: 25.11.20 15:12
Оценка:
ArtDenis:

AD>с учётом того, что скорее всего Tree будет использоваться только при инициализации (как тип аргумента функции инициализации), то можно уменьшить потребление памяти и количество релокаций:

AD>std::variant<std::vector<Tree>, std::initializer_list<int>> val_;

Опередил.

UPD. А почему не оба варианта initializer_list?
Модератор-националист Kerk преследует оппонентов по политическим мотивам.
Отредактировано 25.11.2020 15:55 Bill Baklushi . Предыдущая версия .
Re[5]: initializer_list и неизвестная размерность
От: rg45 СССР  
Дата: 25.11.20 20:33
Оценка: 9 (1)
Здравствуйте, ArtDenis, Вы писали:

AD>Если уж придирки продолжились и с учётом того, что скорее всего Tree будет использоваться только при инициализации (как тип аргумента функции инициализации), то можно уменьшить потребление памяти и количество алокаций:


AD>
AD>struct Tree
AD>{
AD>    std::variant<std::vector<Tree>, std::initializer_list<int>> val_;
AD>    Tree(std::initializer_list<int> children) : val_(children) {}
AD>    Tree(std::initializer_list<Tree> children) : val_(children) {}
AD>};
AD>


Если так, то не очень понятно, для чего здесь нужен std::vector. Можно ведь полностью перейти на std::initializer_list. Ну и параметризация initializer_list двумя разными типами, с моей точки зрения выглядит как не очень оправданное усложнение кода. Ведь initializer_list — это всего лишь пара указателей для которых не нужно никаких аллокаций и копирования контента они за собой не влекут. Я бы переписал так:

template <typename T>
struct Tree
{
    std::variant<T, std::initializer_list<Tree>> val_;
    Tree() = default;
    Tree(const T& v) : val_(v) {}
    Tree(std::initializer_list<Tree> children) : val_(children) {}
};


И я даже пошел бы дальше, не постеснявшись использовать наследование. Имхо, в данном случае наследование вполне естественно и дает сразу готовый к использованию класс:

http://coliru.stacked-crooked.com/a/2ea221fe95d122df

template<typename T>
struct Tree : std::variant<T, std::initializer_list<Tree<T>>>
{
    using variant = std::variant<T, std::initializer_list<Tree>>;
    Tree() = default;
    Tree(const T& t) : variant(t) {}
    Tree(std::initializer_list<Tree> children) : variant(children) {}
};
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 25.11.2020 20:52 rg45 . Предыдущая версия . Еще …
Отредактировано 25.11.2020 20:48 rg45 . Предыдущая версия .
Отредактировано 25.11.2020 20:44 rg45 . Предыдущая версия .
Re[6]: initializer_list и неизвестная размерность
От: Bill Baklushi СССР  
Дата: 25.11.20 21:12
Оценка: 12 (1)
rg45:

R>
R>template<typename T>
R>struct Tree : std::variant<T, std::initializer_list<Tree<T>>>
R>{
R>    using variant = std::variant<T, std::initializer_list<Tree>>;
R>    Tree() = default;
R>    Tree(const T& t) : variant(t) {}
R>    Tree(std::initializer_list<Tree> children) : variant(children) {}
R>};
R>


Мой вариант https://rsdn.org/forum/cpp/7890246.1
Автор: Bill Baklushi
Дата: 25.11.20
запрещает смешивание Tree и int в пределах одного уровня
    Tree(std::initializer_list<int> children) : val_(children) {}
    Tree(std::initializer_list<Tree> children) : val_(children) {}

Но сочетание разной глубины int не запрещает.

Меня всё мучают подозрения, что это можно реализовать на шаблонах, но как, ума не приложу.

Для практических целей вполне сойдёт вариант фиксированной глубины без шаблонов
std::variant<
  std::initializer_list<int>,
  std::initializer_list<std::initializer_list<int>>,
  std::initializer_list<std::initializer_list<std::initializer_list<int>>>,
  std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<int>>>>,
  std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<int>>>>>,
  std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<std::initializer_list<int>>>>>>
  >


(UPD это, оказывается не работает, но работает банальный overload
#include <initializer_list>

typedef std::initializer_list<int>  i0_t;
typedef std::initializer_list<i0_t> i1_t;
typedef std::initializer_list<i1_t> i2_t;
typedef std::initializer_list<i2_t> i3_t;
typedef std::initializer_list<i3_t> i4_t;
typedef std::initializer_list<i4_t> i5_t;
typedef std::initializer_list<i5_t> i6_t;
typedef std::initializer_list<i6_t> i7_t;
typedef std::initializer_list<i7_t> i8_t;
typedef std::initializer_list<i8_t> i9_t;

struct A
{
    A(i0_t){};
    A(i1_t){};
    A(i2_t){};
    A(i3_t){};
    A(i4_t){};
    A(i5_t){};
    A(i6_t){};
    A(i7_t){};
    A(i8_t){};
    A(i9_t){};
};

int main()
{
    A a{{{ 1, 3 }}, {{2, 5 }}};

    return 0;

}


)

А вот в мировом масштабе без потери общности...
Модератор-националист Kerk преследует оппонентов по политическим мотивам.
Отредактировано 27.11.2020 14:12 Bill Baklushi . Предыдущая версия . Еще …
Отредактировано 27.11.2020 11:31 Bill Baklushi . Предыдущая версия .
Re[6]: initializer_list и неизвестная размерность
От: ArtDenis Россия  
Дата: 26.11.20 09:35
Оценка:
Здравствуйте, Bill Baklushi, Вы писали:

BB>UPD. А почему не оба варианта initializer_list?


Тогда был не уверен, но сейчас подумал и решил что можно. Никаких UB из-за использования объектов после вызова деструктора быть не должно, так что всё ок.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[7]: initializer_list и неизвестная размерность
От: Bill Baklushi СССР  
Дата: 27.11.20 11:26
Оценка:
ArtDenis:

BB>>UPD. А почему не оба варианта initializer_list?

AD>Тогда был не уверен, но сейчас подумал и решил что можно. Никаких UB из-за использования объектов после вызова деструктора быть не должно, так что всё ок.

О каком "использовании объектов после вызова деструктора" идёт речь?
Модератор-националист Kerk преследует оппонентов по политическим мотивам.
Re[8]: initializer_list и неизвестная размерность
От: ArtDenis Россия  
Дата: 27.11.20 12:37
Оценка:
Здравствуйте, Bill Baklushi, Вы писали:

BB>О каком "использовании объектов после вызова деструктора" идёт речь?


Речь о самом частом UB при использовании initializer_list, когда initializer_list разрушен, но идёт обращение к объектам, которые в нём хранились. В данном случае все initializer_list (при использовании для передачи в функцию инициализации) будут живыми при доступе из функции инициализации, так что всё нормально
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[9]: initializer_list и неизвестная размерность
От: Bill Baklushi СССР  
Дата: 27.11.20 13:27
Оценка:
ArtDenis:

AD>В данном случае все initializer_list (при использовании для передачи в функцию инициализации) будут живыми при доступе из функции инициализации, так что всё нормально


Ну да, мы же договорились, что Tree используется только при инициализации основного объекта...
Модератор-националист Kerk преследует оппонентов по политическим мотивам.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.