Подтвердить что ты не робот

Инициализируйте С++ (11) std::vector с содержимым другого и дополнительных элементов

Мне нужен "элегантный" способ инициализации вектора в фазе объявления с содержимым другого и несколькими дополнительными элементами.

Я хочу решить следующее:

Рассмотрим следующую (примерную) декларацию с инициализацией:

const std::vector<std::string> c90_types = {
    "char",
    "signed char",
    "unsigned char",
    "short",
    "unsigned short",
    "int",
    "unsigned int",
    "long",
    "unsigned long",
    "float",
    "double",
    "long double"
};

const std::vector<std::string> c99_types = {
    "char",
    "signed char",
    "unsigned char",
    "short",
    "unsigned short",
    "int",
    "unsigned int",
    "long",
    "unsigned long",
    "float",
    "double",
    "long double",
    "long long",
    "unsigned long long",
    "intmax_t",
    "uintmax_t"
};

как вы можете видеть, c99_types имеет подмножество, которое точно c90_types. Я хочу избежать ситуации, когда мне нужно изменить подмножество, а затем вручную изменить "надмножество", чтобы избежать дополнительного шага, который может привести к ошибкам:)

В качестве побочного примечания я не хочу писать код вроде:

second.insert(second.begin(), first.begin(), first.end());
second.push_back(something);

Любые хорошие и чистые решения для этого?

4b9b3361

Ответ 1

Есть трюк под названием "Я хочу инициализировать переменную const с чем-то сложным". что стало возможным с С++ 11, бесстыдно украденным из Javascript.

const std::vector<std::string> c90_types = {
    "char",
    // and so on, and so forth....
};

const std::vector<std::string> c99_types = ([&](){
    const auto additional_types = { // initializer_list<const char *>, but it does not matter.
        "long long",
        "unsigned long long",
        "intmax_t",
        "uintmax_t"
    };

    std::vector<std::string> vec{c90_types};

    vec.insert(vec.end(), additional_types.begin(), additional_types.end());

    return vec;
})();

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

vec перемещается, а не копируется.

Ответ 2

Сначала вы можете определить самый большой вектор (здесь это будет c99_types), а затем построить остальные с итераторами из самого большого.

Вот пример:

const vector<int> a{1,2,3,4};
const vector<int> b{begin(a), begin(a)+2}; // b is {1,2}

Итак, вы можете написать:

const std::vector<std::string> c99_types = {
    "char",
    "signed char",
    "unsigned char",
    "short",
    "unsigned short",
    "int",
    "unsigned int",
    "long",
    "unsigned long",
    "float",
    "double",
    "long double",
    "long long",
    "unsigned long long",
    "intmax_t",
    "uintmax_t"
};

const std::vector<std::string> c90_types{begin(c99_types), begin(c99_types)+12};

Ответ 3

Вариант 1: std::array

Это, вероятно, может быть очищено и улучшено много, но это хотя бы исходная точка (она использует Джонатан Вакели redi::index_tuple:

template<typename T, std::size_t N, unsigned... I, typename ...U>
inline auto
append_array_helper(const std::array<T, N>& array, redi::index_tuple<I...>, U&&... elements) -> std::array<T, N + sizeof...(elements)>
{
    return std::array<T, N + sizeof...(elements)>{ std::get<I>(array)..., std::forward<U>(elements)... };
}

template<typename T, std::size_t N, typename ...U>
inline auto
append_array(const std::array<T, N>& array, U&&... elements) -> std::array<T, N + sizeof...(elements)>
{
    return append_array_helper(array, typename redi::make_index_tuple<N>::type(), std::forward<U>(elements)...);
}

const std::array<std::string, 12> c90_types = {
    "char",
    "signed char",
    "unsigned char",
    "short",
    "unsigned short",
    "int",
    "unsigned int",
    "long",
    "unsigned long",
    "float",
    "double",
    "long double"
};

const std::array<std::string, 16> c99_types = append_array(
    c90_types,
    "long long",
    "unsigned long long",
    "intmax_t",
    "uintmax_t"
);

Если вы не хотите указывать размер массива, вы можете использовать следующий метод:

template<typename T, typename... U>
constexpr auto make_array(U&&... elements) -> std::array<T, sizeof...(elements)>
{
    return { std::forward<U>(elements)... };
}

const auto c90_types = make_array<std::string>(
    "char",
    "signed char",
    "unsigned char",
    "short",
    "unsigned short",
    "int",
    "unsigned int",
    "long",
    "unsigned long",
    "float",
    "double",
    "long double"
);

...

Вариант 2: Макросы

Не мой любимый, но простой и понятный и понятный:

#define C90_TYPES         \
    "char",               \
    "signed char",        \
    "unsigned char",      \
    "short",              \
    "unsigned short",     \
    "int",                \
    "unsigned int",       \
    "long",               \
    "unsigned long",      \
    "float",              \
    "double",             \
    "long double"

#define C99_TYPES         \
    C90_TYPES,            \
    "long long",          \
    "unsigned long long", \
    "intmax_t",           \
    "uintmax_t"

const std::vector<std::string> c90_types = {
    C90_TYPES
};

const std::vector<std::string> c99_types = {
    C99_TYPES
};

Ответ 4

Вы можете использовать boost::join:

#include <vector>
#include <boost/range/join.hpp>

const std::vector<std::string> c90_types = {
  "char",
  "signed char",
  "unsigned char",
  "short",
  "unsigned short",
  "int",
  "unsigned int",
  "long",
  "unsigned long",
  "float",
  "double",
  "long double"
};


auto range = boost::join(c90_types, std::vector<std::string>{
    "long long",
    "unsigned long long",
    "intmax_t",
    "uintmax_t"
});

const std::vector<std::string> c99_types(range.begin(), range.end());

Ответ 5

С дополнительным кодом вы все равно можете иметь const vector:

std::vector<std::string> make_c99_type()
{
    auto res = c90_types;
    const std::vector<std::string> extra_c99_types = {
        "long long",
        "unsigned long long",
        "intmax_t",
        "uintmax_t"
    };
    res.insert(res.end(), extra_c99_types.begin(), extra_c99_types.end());
    return res;
}

const std::vector<std::string> c99_types = make_c99_type();