C : статически инициализировать контейнер данными из другого статически инициализированного контейнера

#c #std #c 20

#c #std #c 20

Вопрос:

Есть ли способ сопоставить ключи / значения одного статически инициализированного контейнера с другим статически инициализирующим? Что-то вроде этого:

 #include <iostream>
#include <set>
using namespace std;

const set< pair< string, int > > my_set = {
    ( "three" , 3  ),
    ( "seven" , 7  ),
    ( "twelve", 12 )
};

//how to statically extract pairs' first values?
const set< string > my_strings = my_set.values().map( []( const auto amp; pair ){ return pair.first; } );

int main() {
    cout << "statically initialized set:" << endl;
    for ( const auto amp; v : my_strings )
        cout << "    " << v << endl;
}
  

Ожидаемый результат:

 statically initialized set:
    three
    seven
    twelve
  

Комментарии:

1. Больше всего вам нужно быть осторожным, если статические данные находятся внутри разных единиц перевода. Текущие ответы предполагают, что данные упорядочены в том же файле, что и ваши вопросы, и вы получили бы другие ответы, если бы это предположение было удалено.

Ответ №1:

С диапазоном-v3:

 const set< string > my_strings =
    my_set 
    | ranges::views::keys
    | ranges::to<std::set>();
  

views::keys есть в C 20, но ranges::to нет.

Комментарии:

1. Для полноты картины, можете ли вы указать часть стандарта, которая гарантирует, что my_set она будет создана раньше my_strings ?

2. @Jeffrey eel.is/c draft/basic.start.dynamic

3. @Barry это справедливо только для материалов в том же TU, верно? В противном случае SIOF?

4. @NoSenseEtAl Да, но вопрос примерно в том же TU.

Ответ №2:

нет необходимости в специальной библиотеке или c 20

 #include <iostream>
#include <set>
using namespace std;

const set< pair< string, int > > my_set = {
    { "three" , 3  },
    { "seven" , 7  },
    { "twelve", 12 }
};

//how to statically extract pairs' first values?
const set< string > my_strings = []{
    set<string> data;
    for(autoamp; pair: my_set){ // or with c  20 : ranges amp; use set's InputIt constructor
        data.insert(pair.first);
    }
    return data;
}();

int main() {
    cout << "statically initialized set:" << endl;
    for ( const auto amp; v : my_strings )
        cout << "    " << v << endl;
}
  

Обратите внимание, что std::set не имеет конструктора constexpr, он не будет выполнять инициализацию во время компиляции.

Комментарии:

1. Спасибо за ответ! my_strings Инициализируется ли в этом случае статически? Что set<> ... = []{}(); означает конструкция? Где я могу прочитать об этом? Заранее спасибо.

2. @Slaus Я не уверен, что вы имеете в виду под statically , да, он будет инициализироваться правильно, и вы не сможете его изменить, но поскольку у std::set него нет constexpr конструктора, он не будет инициализирован во время компиляции (т. Е. Оба my_set и my_strings создаются во время выполнения)

3. Спасибо за ответ. Да, мне было интересно, произойдет ли инициализация во время компиляции или нет. Поэтому я предполагаю, что он инициализируется прямо перед main() началом выполнения…

4. @Slaus и []{}(); это мгновенно вызываемая лямбда-функция (я не заметил, что я не отправил это сообщение: P)

5. @appleapple более распространенное название для этой идиомы — IIFE: выражение функции, вызываемое немедленно