Search code examples
c++scopeargumentsvariable-assignment

Declare a variable of changing type inside a if-statement and using it outside of statement


I have a program that's reading in the command line argument to choose between one of three algorithms. Because each different argument would need a different variable type, I can't create a null variable before the if-statement. How can I set this up so that the program compiles?

std::string argType = argv[1];
if (argType =="Type_A") {
    outPrint="Ty_A";
    AlgoPick<Type_A> algorithm = AlgoPick<Type_A>();
} else if (argType =="Type_B") {
    outPrint="Ty_B";
    AlgoPick<Type_B> algorithm = AlgoPick<Type_B>();
} else {
    outPrint="Ty_O";
    AlgoPick<Type_O> algorithm = AlgoPick<Type_O>();
}

std::cout << algorithm.eval() << std::endl;

Trying to pre-declare the variable and overwrite it led to weird behavior.

AlgoPick<Type_A> algorithm

AlgoPick<Type_B> algorithm = AlgoPick<Type_B>();
/*Trying to do this led to a mesh of both Type_A and Type_B logic instead of just Type_B.*/

Solution

  • If the signature of eval() does not change depending on the template argument, then make AlgoPick<T> derive from a non-template base class, move eval() to that class, and make it virtual. Then use polymorphism to call eval() at runtime.

    class AlgoPickBase {
    public:
        virtual ~AlgoPickBase() = default;
        virtual returnType eval() = 0;
    };
    
    template<typename T>
    class AlgoPick : public AlgoPickBase {
    public:
        returnType eval() override {
            ...
        }
    };
    
    ...
    
    std::string argType = argv[1];
    std::unique_ptr<AlgoPickBase> algorithm;
    if (argType == "Type_A") {
        outPrint = "Ty_A";
        algorithm = std::make_unique<AlgoPick<Type_A>>();
    } else if (argType =="Type_B") {
        outPrint = "Ty_B";
        algorithm = std::make_unique<AlgoPick<Type_B>>();
    } else {
        outPrint = "Ty_O";
        algorithm = std::make_uniqu<AlgoPick<Type_O>>();
    }
    
    std::cout << algorithm->eval() << std::endl;
    

    If that is not an option, then use std::variant for the variable, and std::visit() to call eval() on whatever object is stored in the variant.

    std::string argType = argv[1];
    std::variant<AlgoPick<Type_B>, AlgoPick<Type_B>, AlgoPick<Type_O>> algorithm;
    
    if (argType == "Type_A") {
        outPrint = "Ty_A";
        algorithm = AlgoPick<Type_A>();
    } else if (argType == "Type_B") {
        outPrint = "Ty_B";
        algorithm = AlgoPick<Type_B>();
    } else {
        outPrint = "Ty_O";
        algorithm = AlgoPick<Type_O>();
    }
    
    std::visit(
        [](auto&& alg){
            std::cout << alg.eval() << std::endl;
        }, algorithm
    );