Есть ли способ преобразовать строку в вектор‹int›?

Я относительно новичок в программировании и сейчас изучаю C++. Я сомневаюсь, что моя логика в этом вообще верна, но вот что я пытался выяснить:

У меня есть простая программа, которая выводит размер и содержимое вектора;

vector<int> v1;
vector<int> v2(10);
vector<int> v3(10, 42);
vector<int> v4{ 10 };
vector<int> v5{ 10, 42 };
vector<string> v6{ 10 };
vector<string> v7{ 10, "hi" };
//and so on...........

bool firstPass= true;
for (auto i : v3){
    if (firstPass) cout << "Vector size:  " << v3.size() << ".\nElements: " << i << ", ";
    cout << i << ", ";
    firstPass= false;
}

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

Я пробовал несколько методов, таких как создание vector<string> V8{"v1","v2","v3"..}
for (auto i : V8[counter])

но, по сути, я потерпел неудачу, потому что "v1" != v1. (Именно здесь я получил идею "преобразовать строку в вектор", но что-то подсказывает мне, что это не тот способ сделать это...)

Любая помощь и критика будут очень признательны, и я приношу извинения, так как это, вероятно, будет подано как слишком конкретное или даже бесполезное, учитывая, что мой способ решить эту проблему, вероятно, ошибочен, и я задал неправильный вопрос!


person Boop    schedule 06.08.2014    source источник
comment
Если вы хотите повторять векторы, проще всего поместить их все в итерируемый контейнер, например. другой вектор. Итак, у вас есть vector<vector<int>> = { { }, {10}, {10,42}, {10}, {10,42} };. Затем вы можете выполнять итерацию, используя вложенные циклы for. Но вы не можете так легко смешивать строки — у вас может быть отдельный vector<vector<string>>, или вы можете создать уровень абстракции, используя варианты (boost::any, boost::variant, полиморфную иерархию среды выполнения для векторов)... это, вероятно, выходит за рамки того, что вы Готовы написать.   -  person Tony Delroy    schedule 06.08.2014
comment
Или, если ваши векторы уже существуют, вы можете создать вектор (или просто список инициализаторов) указателей на существующие векторы. (Но вам все равно понадобятся отдельные наборы векторов разных типов.)   -  person happydave    schedule 06.08.2014
comment
@TonyD, вектор векторов звучит великолепно, но меня конкретно мучает та же проблема, что и раньше; как бы я добавил огромное количество существующих векторов в vector<vector<int>> без необходимости vectorOfVectors.push_back(vectorName) для каждого вектора? Следующий код будет каждый раз записывать v1,v2,v3 вместо vectorName, но это будут строки и, следовательно, неправильного типа: vectorOfVectors.push_back("v"+to.string(counter)) counter++;   -  person Boop    schedule 06.08.2014
comment
@Boop, язык работает не так. Вы должны обращаться к элементам вашей цели каким-то образом, и в C++ это в конечном итоге начинается с id во время компиляции; не время выполнения. этот идентификатор может быть вектором векторов, массивом, что у вас есть, но он должен быть известен во время компиляции каким-то образом. Если бы это был ваш собственный класс, вы могли бы поддерживать динамический статический список объектов и просто сбрасывать список, но стандартная библиотека не предоставляет такой возможности. Возможно шаблон-обертка, но я не понимаю, стоит ли заморачиваться. предварительная обработка с переменным числом аргументов может быть полезной, но опять же, вы должны хотеть этого плохо.   -  person WhozCraig    schedule 06.08.2014
comment
@Boop: сколько у тебя таких векторов?   -  person Tony Delroy    schedule 06.08.2014
comment
@TonyD В исходном упражнении ничего этого не было. Это была идея, которая меня беспокоила, просто казалось, что у должно быть решение :) Спасибо за вашу обширную помощь!   -  person Boop    schedule 06.08.2014
comment
Как указано в моем ответе, вы можете искать переменные по имени строки, используя POSIX dlsym(), но он работает только с глобальными переменными.   -  person jxh    schedule 06.08.2014


Ответы (5)


Чтобы решить вашу буквальную проблему поиска переменной по строке, представляющей имя переменной: единственное средство, которое POSIX предоставляет для поиска глобальной переменной по имени, - это dlsym(). Это работает только для глобальных переменных, и вы должны объявить свои функции с помощью extern "C", чтобы подавить искажение имен C++ (имена глобальных переменных не искажаются).

#include <vector>
#include <assert.h>
#include <dlfcn.h>

std::vector<int> v1;

int main () {
    void *h = dlopen(0, RTLD_NOW);
    void *v = dlsym(h, "v1");
    assert(v == &v1);
}

Чтобы приведенный выше пример работал, вам нужно скомпилировать его с помощью g++ -rdynamic prog.cpp -ldl.

Ограничение этого метода заключается в том, что вам нужно знать тип возвращаемого указателя априори и соответствующим образом его приводить.

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

template <typename Vector>
void print_all_vectors (Vector v) {
    /* enforce we are only interested in vectors */
    const std::vector<typename Vector::value_type> &vr = v;
    std::cout << "Vector size:  " << vr.size() << ".";
    if (!vr.empty()) std::cout << "\nElements";
    bool first = true;
    for (auto i : vr) {
        std::cout << (first ? ": " : ", ") << i;
        first = false;
    }
    std::cout << '\n';
}

template <typename Vector, typename... Vectors>
void print_all_vectors (Vector v, Vectors... vectors) {
    print_all_vectors(v);
    print_all_vectors(vectors...);
}

Первый шаблон в приведенном выше коде выводит вектор. Вторая функция шаблона рекурсивно распаковывает список вариативных параметров и передает каждый из них первой функции шаблона.

Использовать функции легко, как показано ниже:

std::vector<int> v1{1, 3, 5, 7};
std::vector<std::string> v2{"doh", "ray", "me"};
print_all_vectors(v1, v2);
person jxh    schedule 06.08.2014

Вам понадобится С++ 11, но это определенно возможно:

template<typename V>
void PrintVector(V const& v) {
  for (auto elem : v) std::cout << elem << " ";
  std::cout << std::endl;
}
template <typename V, typename ... Vectors>
void PrintAll(V const& v1, Vectors... vtail)
{
   PrintVector(v);
   PrintAll(vtail...);
}
PrintAll(v1, v2, v3, v4, v5, v6, v7, v8, v9);
person MSalters    schedule 06.08.2014
comment
+1 не уверен, что это то, что было нужно (жалоба вопроса «V1!= v1» заставила меня подумать, что какой-то способ обработки идентификаторов больше похож на текст — с конкатенацией — был желателен), но перечитав вопрос, vector V8{"v1","v2","v3"..} предполагает, что ОП открыт для таких подход, и это делает это очень элегантно.... - person Tony Delroy; 06.08.2014
comment
@TonyD: ОП уже признает, что его идея со строками, вероятно, была неправильным подходом для начала. В конце концов, вам нужен какой-нибудь способ сообщить компилятору, какие объекты нужно сгруппировать вместе. Очевидно, что вы не можете просто распечатать каждый вектор в программе. Что, если бы std::cout использовал его внутренне?! - person MSalters; 06.08.2014
comment
все ваши отдельные точки верны, но они заставляют это звучать как список, набранный программистом, или какой-то наивный (и в текущем С++ несуществующий) самоанализ - единственные альтернативы. В любом случае, я уверен, что мы оба знаем, что предлагается и каковы альтернативы — массивы/векторы/template <int N> .../итерация препроцессора/dlsym с использованием некоторого соглашения об именах/скрипты генерации кода и т. д. и т. д. и т. д. - person Tony Delroy; 06.08.2014
comment
@TonyD: Кислый виноград, так как это в основном мой ответ, опубликованный часом ранее. - person jxh; 06.08.2014

Вам нужно что-то для итерации, если вам нужно что-то, что разрешается во время выполнения, вы можете использовать вектор векторов, но они должны быть одного типа (вектор строк, смешанный с int, невозможен, поскольку они разные типы из-за экземпляр шаблона) С другой стороны, вы можете использовать препроцессор и расширение макроса для статических вещей или шаблонов.

person martin    schedule 06.08.2014

(Это скорее комментарий, чем ответ, но я перечисляю слишком длинный код для комментария...)

Если вы не хотите очищать код, чтобы только иметь vector<vector<int>> + vector<vector<string>>, vector<vector<boost::variant<int,string>>> или подобное, вы можете создать, например. vector<vector<int>*> и vv.push_back(&v1); vv.push_back(&v2); и др., чтобы избежать затрат на копирование.

Невозможно просто выполнить итерацию по переменным с именами v1, v2, v3 и т. д. (препроцессор может это сделать, но это сложно — смотрите библиотеку препроцессора boost, если хотите продолжить).

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

vector<vector<int>>& operator<<(vector<vector<int>>& vv, vector<int>& v)
{
    vv.push_back(v);
    return vv;
}

Тогда вы можете кодировать ...

vv << v1 << v2 << v3 << v4 << v5;

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

person Tony Delroy    schedule 06.08.2014
comment
Самый простой способ перебрать {v1, v2, v3, v4, v5, v6, v7, v8} — использовать вариативные шаблоны. Препроцессор Boost — это хак до C++11. - person MSalters; 06.08.2014
comment
@MSalters: проблема заключается в генерации такого кода - с помощью препроцессора вы можете создать несколько #define X, чтобы X(v, 1, 1000) заменили v1, v2, v3, v4..., v999, v1000, а затем передать вывод в шаблон с переменным числом переменных, встроить его в initialiser_list или что вам нужно. Это определенно хакерский подход, но все еще есть области полезности, не затронутые C++11. - person Tony Delroy; 06.08.2014
comment
TBH Я бы использовал метапрограммирование шаблонов для определения v<1>, v<2>, ... в таких случаях. Если v1 и v2 связаны этим, они не должны использовать два разных идентификатора. - person MSalters; 06.08.2014
comment
@MSalters: и так далее ... прокомментировал ОП. Это была идея, которая меня беспокоила, просто казалось, что у чего-то должно быть решение, поэтому то, что разумно / лучше всего, отсутствовало с самого начала. идти. - person Tony Delroy; 06.08.2014

Если вы просто преобразуете string в vector<int>, то этот пример может дать вам общее представление о том, как это сделать.

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    string str = "1234567890";
    vector<int> intedStr;

    for (size_t i = 0; i < str.length(); i++)
    {
        intedStr.push_back((int)str[i] - '0');
    }
    for (size_t i = 0; i < intedStr.size(); i++)
    {
        cout << intedStr[i] << " ";
    }

    system("pause");
}

Примечание. это не безопасная функция. Что произойдет, если вы захотите преобразовать "abcsd" в vector<int>?

person AK_    schedule 06.08.2014