Установить тип вектора во время выполнения - PullRequest
3 голосов
/ 15 сентября 2009

У меня есть программа, которая должна установить тип вектора при выполнении программы (в соответствии со значением в файле конфигурации).

Я пробовал это:

int a = 1

if(a == 1)  vector<int> test(6);
else  vector<unsigned int> test(6);

test.push_back(3);

Но это дает мне:

Error   1   error C2065: 'test' : undeclared identifier

Я не совсем уверен, почему, но я думаю, что это потому, что вектор на самом деле не определяется во время компиляции, поэтому компилятор не может работать с ним во время компиляции остальной части кода.

Есть ли способ определить тип вектора во время выполнения, аналогичный тому, который я пытался описать выше? Я попытался создать одну версию вне if, а затем удалить ее и переписать новую версию внутри IF. Это, однако, кажется неправильным, и я все равно не могу заставить его работать. спасибо.

Ответы [ 7 ]

13 голосов
/ 15 сентября 2009

Причина, по которой это не работает, заключается в том, что вы объявляете векторы внутри блока if- и else соответственно, поэтому они выходят за пределы области действия после завершения этого блока.

Есть ли способ определить тип вектора во время выполнения, аналогичный тому, который я пытался описать выше?

Нет, тип переменной должен быть известен во время компиляции. Единственный вариант - поместить строку test.push_back(3), а также любой следующий код, который обращается к test, в блок if- и else или избежать дублирования кода во второй шаблонной функции. Это может выглядеть так:

template <class T>
do_something_with_test(vector<T>& test) {
    test.push_back(3);
    // work with test
}

void foo() {
    int a = 1

    if(a == 1) {
        vector<int> test(6);
        do_something_with_test(test);
    }
    else {
        vector<unsigned int> test(6);
        do_something_with_test(test);
    }
}
4 голосов
/ 15 сентября 2009

Точная причина ошибки, которую вы получаете, довольно тонкая для начинающего, и включает в себя область действия переменной test, которую вы создаете. Проще говоря, вы создаете вектор внутри оператора if, но к тому времени, когда вы собираетесь его использовать, он больше не существует, поскольку он вышел из области видимости.

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

if(a == 1)
{
  vector<int> test(6);
}
else
{
  vector<unsigned int> test(6);
}

test.push_back(3);

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

3 голосов
/ 15 сентября 2009

Я не уверен, зачем вам это нужно, но я предлагаю вам попробовать использовать вектор объединения для решения вашей проблемы, что-то вроде этого

union DataType
{
    int intVal;
    unsigned uintVal;
}
std::vector<DataType> vec;

Или, возможно, более элегантный способ - использовать boost :: variable вместо объединения. Возможно, если вы расскажете нам более подробно о своей проблеме, вы получите гораздо лучший ответ.

Удачи!

2 голосов
/ 15 сентября 2009

Вы можете взглянуть на boost :: any , чтобы достичь чего-то похожего.

1 голос
/ 15 сентября 2009

Установка типа вектора (он же создание шаблона ) всегда происходит во время компиляции. Для получения дополнительной информации просмотрите статью в Википедии о Шаблонное метапрограммирование .

0 голосов
/ 28 ноября 2011

если вам действительно нужен полиморфный тип, возможно, вы могли бы взглянуть на класс boost :: option или что-то подобное;
Это разработано для имитации некоторых поведений динамических языков в C ++ и обычно используется для взаимодействия (или реализации) с ними. Вы можете создать "vector a" и a.push_back (Variant ((unsigned int) ..)). Конструкторам для выдаваемых значений требуется тип времени компиляции.

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

но гораздо более вероятно, что вы можете достичь желаемого конечного результата без такого механизма, возможно, переделав вашу программу, чтобы избежать проверок типов во время выполнения (что, скорее всего, сведет на нет некоторые преимущества использования C ++ по сравнению с другим языком в первую очередь). ).

Вы можете написать зависимые от типа детали в виде шаблонов (как предложено выше) и выбрать альтернативный путь к коду на основе настроек файла конфигурации, проверенных и отправленных один раз. Этот стиль кодирования становится немного проще в c ++ 0x с помощью 'auto' и decltype ().

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

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

0 голосов
/ 15 сентября 2009

В вашем примере у вас есть независимые экземпляры переменной test, созданные в каждой ветви вашего оператора if, каждый из которых немедленно выходит за рамки. Поэтому, когда компилятор получает значение test.push_back(3);, в области видимости нет переменной test, поэтому возникает ошибка.

Чтобы решить вашу проблему, вы не можете бороться с системой типов: если предположить, что int и unsigned int являются реальными типами, о которых вы говорите, вам будет гораздо лучше использовать vector<int> повсеместно, предполагая, что на самом деле нужен полный диапазон беззнаковых int.

...