Есть ли способ инициализировать вектор по индексу в C ++ 11? - PullRequest
0 голосов
/ 19 февраля 2020

Легко заполнить элементы вектора индексом после его инициализации:

std::vector<int> myVector {0, 0, 0};
int indexOfInterest = 1;
myVector[indexOfInterest] = 999;
// myVector now contains {0, 999, 0}

Однако есть ли способ инициализировать вектор непосредственно индексом? indexOfInterest может измениться в моем коде в будущем, и я хотел бы избежать жесткого кодирования вектора с помощью

std::vector<int> myVector {0, 999, 0};

. Есть ли какой-нибудь синтаксис, такой как

int indexOfInterest = 1;
std::vector<int> myVector[3] {indexOfInterest : 999}; // this is made-up syntax!
// desired: myVector contains {0, 999, 0} and is 3 elements large

, который можно использовать в C ++ 11 для достижения этого эффекта?

Ответы [ 4 ]

2 голосов
/ 19 февраля 2020

Нет, такого нет в C ++ 11. Если бы только один индекс нуждался в инициализаторе, отличном от всех остальных, я бы не использовал ничего, кроме

std::vector<int> myVector(3);
myVector[1] = 999;

. Думаю, было бы не сложно написать какой-нибудь поддельный класс итератора, который бы позволяет вам написать что-то вроде

auto pit = pair_of_fake_iterators(3,1,999);
std::vector<int> myVector( pit.first, pit.second);

, который вызывает конструктор, который принимает два итератора и «копирует» элементы. Хотя я бы не стал там. Это ничего не экономит при наборе текста, и читатели вашего кода будут аплодировать за уровень запутывания.

1 голос
/ 19 февраля 2020

Другой способ сделать это - использовать std::unordered_map. Не совсем то же самое, но может работать для вас в зависимости от того, что вы делаете:

std::unordered_map<int, int> mp{ { indexOfInterest, 999} };
mp[someOtherIndex] = 42;

Все индексы, которым вы ничего не присвоили, будут иметь значение по умолчанию (в данном случае 0), когда Вы пытаетесь получить к ним доступ.

0 голосов
/ 19 февраля 2020

В комментариях, которые вы упоминаете, это необходимо для инициализации вектора в списке инициализатора члена.

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

some_constructor(...) : myVector([]{
    std::vector<int> vec(3);
    myVector[indexOfInterest] = 999;
    return vec;
}()) {
}

Вы также можете написать себе обобщенную c функцию для задачи, например:

template<typename T, std::size_t N>
std::vector<T> make_vector(typename std::vector<T>::size_type size, const T& value, std::pair<typename std::vector<T>::size_type, T>(&&entries)[N]) {
    std::vector<T> vec(size, value);
    for(auto& entry : entries)
        vec[entry.first] = std::move(entry.second);
    return vec;
}

template<typename T, std::size_t N>
std::vector<T> make_vector(typename std::vector<T>::size_type size, std::pair<typename std::vector<T>::size_type, T>(&&entries)[N]) {
    return make_vector<T>(size, {}, entries);
}

Это можно использовать в инициализаторе члена, например, так:

some_constructor(...) : myVector(make_vector(3, 0, {{indexOfInterest, 999}})) {
}

или

some_constructor(...) : myVector(make_vector<int>(3, {{indexOfInterest, 999}})) {
}

со второй перегрузкой.

Вместо массива вы также можете принять аргумент в качестве std::initializer_list<...> с той разницей, что создается версия массива новые функции для каждого размера списка, данного вызову, в то время как список инициализатора будет использовать одну и ту же функцию для разных размеров списка.

Функция в любом случае не копирует построенный вектор. Однако он может перемещать его один раз (C ++ 17, из-за обязательного удаления копии, за исключением vec в возвращаемое значение) или несколько раз (до C ++ 17). Все эти могут , однако, могут быть оптимизированы компилятором из-за оптимизации (именованного) возвращаемого значения .

0 голосов
/ 19 февраля 2020

Пока вы хотите, чтобы все в векторе было одинаковым, за исключением одного значения, которое вы хотите различать, вы можете использовать

std::vector<int> myVector(size_of_vector, /* some_value_here_if_you_do_not_want_0 */);
myVector[index_you_care_about] = value;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...