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

Использование переменной, которая была определена в выражении if перед

int main() {
    if(i = 0) {
        myclass1 a = "Example1";
    }
    else {
        myclass2 a = "Example2";
    }
    cout << a << endl;
}

Я знаю, как это сделать, это определить его вне блока, но что, если я не решил, какой тип a находится перед проверкой состояния i?

4b9b3361

Ответ 1

Если вы можете использовать вы можете использовать std::variant или std::any если ваши типы не имеют общего базового класса. Эти классы являются безопасными для типов контейнеров для любых или определенных типов. Пример с std::variant может быть следующим:

#include <iostream>
#include <string>
#include <variant>

int main() {
    bool input = false;
    std::cin >> input;

    std::variant<int, long, double, std::string> myVariant;
    if(input)
        myVariant = "Example1";
    else
        myVariant = 3.14;

    std::visit([](auto&& arg) { std::cout << arg << std::endl; }, myVariant);
}

Вместо you также можно использовать boost::variant или boost::any.

Ответ 2

С++ - это статически типизированный язык и требует, чтобы тип переменных использовался в коде, который должен быть известен во время компиляции.

Невозможно написать программу на С++, где скомпилирован оператор типа std::cout << a;, а тип a неизвестен до времени выполнения.

Для этого вам нужен динамически типизированный язык, например, Python или JavaScript.

Ответ 3

Вы можете попробовать polymorphism. Предполагая, что myclass1 и myclass2 "реализуют" класс под названием myclass, вы можете сделать что-то вроде этого:

int main() {
    myclass*a;
    if (i=0) {
        a = new myclass1("Example1");
    } else {
        a = new myclass2("Example2");
    }
    cout<<*a<<endl;
}

Если вы хотите активно использовать тип myclass1 или myclass2 позже, вы можете использовать dynamic_cast, но в зависимости от ваши потребности и то, какое поведение вы реализуете в своих унаследованных классах и ваш базовый класс, может не понадобиться.

Примечание. Я использую здесь необработанный указатель, так как это недолговечный объект и он очищает программу. Я рекомендую вам прочитать интеллектуальные указатели и использовать их соответствующим образом, чтобы избежать утечек памяти. Остерегайтесь утечек памяти на некоторых платформах, которые сохраняются до перезагрузки, может потребоваться вручную освободить (удалить) выделенную память. Подробнее обо всем этом здесь.

Ответ 4

int main() {
    auto call = [](auto a) {
        std::cout << a << std::endl;
    };

    if(i = 0)
        call(myclass1 { "Example1" });
    else 
        call(myclass2 { "Example2" });
}

Ответ 5

Это окончательно требует полиморфизма, и, при желании, если вы хотите, чтобы он был немного более изящным, factory pattern. Шаблон factory не является волшебным, он просто скрывает if в красивой обертке.

Почему бы не использовать другой подход, например, std::variant, который в основном скрывается union? Хорошо, если вы можете хранить разные вещи или даже любые типы (std::any) под тем же именем, но это не очень полезно, так как вы также хотите сделать что-то значимое для объекта. Если вы хотите делать совершенно разные, несвязанные вещи, тогда у вас также могут быть разные объекты, охваченные блоками if (и с совершенно другим кодом). Если, однако, вы хотите делать то же или похожие вещи на разных объектах, то они (обычно) должны быть одинаковыми или связанными типами.

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

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

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

Ответ 6

Я попытаюсь дать вам практический ответ, предполагающий, что вы привыкли делать подобные вещи в JavaScript или что-то еще, и просто пытаетесь написать код на С++.

Во-первых, вы должны понимать, что в С++, cout << a. На самом деле можно назвать совершенно другой метод в зависимости от типа a. По этой причине нет смысла писать cout << a, когда вы ничего не знаете об этом типе. Фактически, вы ничего не можете сделать с помощью a, если вы не знаете достаточно о типе для С++, чтобы решить, какой метод или оператор вы хотите вызвать.

Если у обоих ваших классов есть приемлемая общая база, вы можете сделать что-то следующее:

int main() {
    base_class *pa;
    my_class1 a1;
    my_class2 a2;

    if(i = 0) {
        a1 = "Example1";
        pa = &a1;
    }
    else {
        a2 = "Example2";
        pa = &a2;
    }
    cout << *pa << endl;
}

Обратите внимание, что при написании cout << *pa вы не обязательно должны использовать тот же метод, который будет использоваться cout << a. В первом случае вы вызываете метод, который знает, как выводить все подклассы base_class, а во втором случае вы можете вызвать метод, который был написан специально для myclass1 или myclass2.

Если нет приемлемого базового класса, тогда мы просто не будем писать код, подобный этому в С++:

int main() {
    if(i = 0) {
        myclass1 a = "Example1";
        cout << a << endl;
    }
    else {
        myclass2 a = "Example2";
        cout << a << endl;
    }
}

Помните, что два метода, которые вызывают в этих случаях, могут быть совершенно разными методами. Это точно так же, как вызов cout.printClass1(a) vs. cout.printClass2(a). С++ позволяет использовать одно и то же имя для совершенно разных методов, когда он может определить, какой из них вы хотите вызывать на основе типов аргументов.

В JavaScript нет никакой магии, которая могла бы автоматически выбирать между printClass1 и printClass2 при написании cout.callWhatever(a), а также не С++. На обоих языках, если вам нужно вызывать совершенно разные методы для myclass1 vs. myclass2, тогда вы пишете разные вызовы.

Ответ 7

У меня был такой код сам, когда я действительно пытался использовать разные варианты одного и того же кода. Тогда я понял, что лучшим вариантом будет использование препроцессора #if, и он решил мою проблему:

#define VARIATION 2

...

#if VARIATION == 1
    myclass1 a = "Example1";
#else
    myclass2 a = "Example2";
#endif

Я знаю, что это, вероятно, не решает, но, по крайней мере, это обходной путь.

Ответ 8

Если это конкретная проблема, я бы подумал, что это будет намного проще

int main(){
    if(i == 0)          //You wrote i=0 !! silly mistake
        std::cout << myclass1("Example1");
    else
        std::cout << myclass2("Example2");
}

или вы можете выбрать

template<class T>
void foo(T out)
{
    std::cout << out;
}

int main()
{
    if( i==0 )
        foo(myclass1("ex1"));
    else
        foo(myclass2("ex2"));
}

else

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