Как взять количество элементов из инициализатора?
От: drVanо Россия https://vmpsoft.com
Дата: 20.01.24 09:38
Оценка:
Вот тут хочется на автомате передать количество элементов в инициализаторе в поле size:

    struct token_encoding_t
    {
        token_type_id types[20];
        uint8_t size;
        uint8_t bits;
    };


Сейчас приходится писать руками, может быть есть способ лучше.
Отредактировано 20.01.2024 9:39 drVanо . Предыдущая версия .
Re: Как взять количество элементов из инициализатора?
От: reversecode google
Дата: 20.01.24 09:47
Оценка:
types и size объединять в одну сущность
и там constexpr конструктором через initialization_list подсчитать

или натянуть вариадик конструктор на текущую структуру
там размерность из вариадиков можно будет взять
но тогда скорее всего types[20] будет плавать по размеру изза вариадиков
но тогда и size нафиг не нужен
ибо sizeof(types) == size
Re[2]: Как взять количество элементов из инициализатора?
От: drVanо Россия https://vmpsoft.com
Дата: 20.01.24 09:55
Оценка:
Здравствуйте, reversecode, Вы писали:

R>types и size объединять в одну сущность

R>и там constexpr конструктором через initialization_list подсчитать

Можно кинуть примером?

R>или натянуть вариадик конструктор на текущую структуру

R>там размерность из вариадиков можно будет взять
R>но тогда скорее всего types[20] будет плавать по размеру изза вариадиков
R>но тогда и size нафиг не нужен
R>ибо sizeof(types) == size

Про вариадики не понял. Код бегает по конкретному типу.
Re: Как взять количество элементов из инициализатора?
От: andrey.desman  
Дата: 20.01.24 10:00
Оценка: 4 (1) +1
Здравствуйте, drVanо, Вы писали:

V>Сейчас приходится писать руками, может быть есть способ лучше.


конструктор написать. Или что-то такое:
template<typename... Args>
constexpr token_encoding_t makeEnc(uint8_t bits, Args... args) {
    return {{args...}, sizeof...(Args), bits};
}


или все сразу.
Re[3]: Как взять количество элементов из инициализатора?
От: reversecode google
Дата: 20.01.24 10:02
Оценка:
Здравствуйте, drVanо, Вы писали:

V>Здравствуйте, reversecode, Вы писали:


R>>types и size объединять в одну сущность

R>>и там constexpr конструктором через initialization_list подсчитать

V>Можно кинуть примером?


https://en.cppreference.com/w/cpp/utility/initializer_list
Re[2]: Как взять количество элементов из инициализатора?
От: drVanо Россия https://vmpsoft.com
Дата: 20.01.24 10:11
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>конструктор написать. Или что-то такое:

AD>
AD>template<typename... Args>
AD>constexpr token_encoding_t makeEnc(uint8_t bits, Args... args) {
AD>    return {{args...}, sizeof...(Args), bits};
AD>}
AD>


Спасибо, проще наверное засунуть в в конец списка как-нить "стоп" тип и убрать size из структуры совсем.
RE: Как взять количество элементов из инициализатора?
От: serg_joker Украина  
Дата: 20.01.24 10:56
Оценка: 22 (3)
Здравствуйте, drVanо, Вы писали:

V>Сейчас приходится писать руками, может быть есть способ лучше.

Способов много, например здесь
Отредактировано 20.01.2024 10:57 serg_joker . Предыдущая версия .
Re[3]: Как взять количество элементов из инициализатора?
От: K13 http://akvis.com
Дата: 20.01.24 15:33
Оценка:
V>Спасибо, проще наверное засунуть в в конец списка как-нить "стоп" тип и убрать size из структуры совсем.

А на входе ТОЛЬКО константные списки инициализации? или рантайм-наборы имеют право на существование?
так по идее просто напрашивается span если есть гарантия, что список инициализиации никуда не пропадет и не изменится -- тогда хранить можно просто span без всякого массива

Если нужен именно массив, причем именно "стандартного размера" и size для реально используемых -- тоже не проблема ни разу

https://coliru.stacked-crooked.com/a/2475056880b1ac10

#include <iostream>
#include <initializer_list>
#include <cstdint>

enum class token_type_id { A, B, C, D };

struct token_encoding_t
{
    token_type_id types[20];
    uint8_t size;
    uint8_t bits;
    
    template< typename Iterator >
    constexpr token_encoding_t( uint8_t bits_, Iterator begin, Iterator end ): bits{ bits_ }
    {
        for ( size = 0; begin != end && size < std::size(types); ++begin )
            types[size++] = *begin;
    }
    
    template< std::size_t N >
    constexpr token_encoding_t( uint8_t bits_, const token_type_id (&arr)[N] ): token_encoding_t( bits_, std::begin(arr), std::end(arr) ) {}
    
    constexpr token_encoding_t( uint8_t bits_, std::initializer_list<token_type_id> lst ): token_encoding_t( bits_, lst.begin(), lst.end() ) {}
    
    template< typename... Args >
    constexpr token_encoding_t( uint8_t bits_, Args... args ): token_encoding_t( bits_, std::initializer_list<token_type_id>{ args... } ) {}
};

std::ostream& operator<<( std::ostream& o, const token_encoding_t& x )
{
    o << "{bits:" << (int)x.bits << ", size:" << (int)x.size << ", types [";
    for ( int i = 0; i < x.size; ++i )
    {
        if ( i != 0 )
            o << ", ";
        o << (int)x.types[i];
    }
    o << "]";
    return o;
}

int main()
{
    token_type_id arr[] = { token_type_id::A, token_type_id::D, token_type_id::D, token_type_id::B };
    std::cout << token_encoding_t( 4, std::begin(arr), std::end(arr) ) << "\n";
    std::cout << token_encoding_t( 3, arr ) << "\n";
    std::cout << token_encoding_t( 3, { token_type_id::B, token_type_id::C, token_type_id::A } ) << "\n";
    std::cout << token_encoding_t( 5, token_type_id::B, token_type_id::C, token_type_id::A ) << "\n";
    return 0;
}

выдает
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
{bits:4, size:4, types [0, 3, 3, 1]
{bits:3, size:4, types [0, 3, 3, 1]
{bits:3, size:3, types [1, 2, 0]
{bits:5, size:3, types [1, 2, 0]
Re[4]: Как взять количество элементов из инициализатора?
От: Videoman Россия https://hts.tv/
Дата: 21.01.24 10:40
Оценка:
Здравствуйте, K13, Вы писали:

K13>Если нужен именно массив, причем именно "стандартного размера" и size для реально используемых -- тоже не проблема ни разу


Работает, только вот этот конструктор:
constexpr token_encoding_t( uint8_t bits_, Iterator begin, Iterator end )
не может быть использован в выражениях времени компиляции, хотя и помечен как constexpr
Re[5]: Как взять количество элементов из инициализатора?
От: serg_joker Украина  
Дата: 22.01.24 09:57
Оценка: +1
Здравствуйте, Videoman, Вы писали:

V>Работает, только вот этот конструктор:
V>constexpr token_encoding_t( uint8_t bits_, Iterator begin, Iterator end )
V>
не может быть использован в выражениях времени компиляции, хотя и помечен как constexpr


В constexpr ф-циях, исполняемых в константном контексте, запрещены UB.
Добавь в конструктор инициализацию хвоста:
while (size < std::size(types))
    types[size++] = token_type_id{};
Re[6]: Как взять количество элементов из инициализатора?
От: Videoman Россия https://hts.tv/
Дата: 23.01.24 11:32
Оценка: +1
Здравствуйте, serg_joker, Вы писали:

_>В constexpr ф-циях, исполняемых в константном контексте, запрещены UB.

_>Добавь в конструктор инициализацию хвоста:
_>
_>while (size < std::size(types))
_>    types[size++] = token_type_id{};
_>


Это всё понятно. Жалко что в С++17 такой подход не прокатит.
Re: Как взять количество элементов из инициализатора?
От: Кодт Россия  
Дата: 25.01.24 16:17
Оценка:
Здравствуйте, drVanо, Вы писали:

Что-нибудь типа такого?
V>
V>    struct token_encoding_t
V>    {
V>        token_type_id types[20];
V>        uint8_t size;
V>        uint8_t bits;

        token_encoding_t(std::initializer_list<token_type_id> ts) {
            assert(std::size(ts) <= std::size(types));
            std::copy(std::begin(ts), std::end(ts), std::begin(types));
            size = std::size(ts);
            bits = ?????;
        }

        // или такого
        constexpr token_encoding_t(auto... ts) {
            assert(sizeof...(ts) <= std::size(types));
            int i = 0;
            ((types[i++] = ts), ...);
        }

V>    };
V>
Перекуём баги на фичи!
Отредактировано 25.01.2024 16:22 Кодт . Предыдущая версия .
Re: Как взять количество элементов из инициализатора?
От: rg45 СССР  
Дата: 26.01.24 12:21
Оценка:
Здравствуйте, drVanо, Вы писали:

V>Вот тут хочется на автомате передать количество элементов в инициализаторе в поле size:


V>
V>    struct token_encoding_t
V>    {
V>        token_type_id types[20];
V>        uint8_t size;
V>        uint8_t bits;
V>    };
V>


V>Сейчас приходится писать руками, может быть есть способ лучше.


Немного оффтопа. Не очень хорошо то, что поля types и size находятся в прямом досттупе и пользователь может модифицировать их независимо друг от друга и тем самым создать рассогласование данных. По-хорошему, такие вещи нужно прятать в закрытой секции и предоставлять безопасный открытый интерфейс, который будет гарантировать согласованность данных. Как вариант, можно написать собственный контейнер общего применения (что-то типа limited_size_vector) и использовать его вместо пары массив-размер. Все сказанное можно проделать с сохранением возможности использования в компайл-тайм (constexpr). И что примечательно, если так сделать, то проблема инициализации поля size решится автоматически. Ведь если разобраться, то эти две проблемы тесно связаны между собой.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 26.01.2024 12:27 rg45 . Предыдущая версия . Еще …
Отредактировано 26.01.2024 12:22 rg45 . Предыдущая версия .
Re: Как взять количество элементов из инициализатора?
От: fk0 Россия https://fk0.name
Дата: 27.01.24 11:25
Оценка: -1
Здравствуйте, drVanо, Вы писали:

V>Вот тут хочется на автомате передать количество элементов в инициализаторе в поле size:


V>
V>    struct token_encoding_t
V>    {
V>        token_type_id types[20];
V>        uint8_t size;
V>        uint8_t bits;
V>    };
V>


V>Сейчас приходится писать руками, может быть есть способ лучше.


Привёл огромную портянку кода, все его дизассемблировали и сразу поняли, откуда ты там решил, что нужно писать 4 и 2.
Re[2]: Как взять количество элементов из инициализатора?
От: serg_joker Украина  
Дата: 27.01.24 18:08
Оценка:
Здравствуйте, fk0, Вы писали:

fk0> Привёл огромную портянку кода, все его дизассемблировали и сразу поняли, откуда ты там решил, что нужно писать 4 и 2.

Многим удалось, да.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.