What should I do if I have to declare a variable when I don't know the type for it?

Viewed 98

I have code like this

if (...) {
    const auto & h = std::make_shared<ClassB>();
    ... // here may be the function that uniquely belongs to ClassB
    ...
}
else (...) {
    const auto & h = std::make_shared<ClassC>();
    ... // here may be the function that uniquely belongs to ClassC
    ...
}
h->someFunction();

The last line of the above code is invalid because I use a variable that is declared inside the if-else clause. To use h I have to declare it before the if-else clause. But I can't because I don't know what type h belongs to before entering it.

I know I can declare it using ternary operator. But I don't want to because I think it will be redundant to have both ternary operator and if-else clause. Sorry, I can't. The compiler will complain "error: conditional expression is ambiguous;".

Are there any ways to keep only one if-else clause (no ternary operator) and I still can refer to h outside that if-else clause?

2 Answers

I can't [use a ternary operator]. The compiler will complain "error: conditional expression is ambiguous;".

You can, you just have to disambiguate the type of the result by casting one of the two expressions to a base class pointer:

auto const h = …
    ? init_class_b()
    : static_cast<std:unique_ptr<BaseClass>>(init_class_c());

Here, init_class_* are functions/lambdas which contain the body of your two if branches. That is, they create the object and run the unique functions on them. But as a point of code design, if such unique operations are needed, shouldn’t they go into the class constructors?

(Unlike in your code I haven’t made h a reference. Lifetime extension for const references is tricky and isn’t necessary here.)

It is hard to say what the best approach is. You can declare h outside of your if-statement:

auto h = std::shared_ptr<SuperClass>{};  // is now nullptr

if (...) {
    h = std::make_shared<ClassB>
    ... // here may be the function that uniquely belongs to ClassB
    ...
}
else (...) {
    h = std::make_shared<ClassC>
    ... // here may be the function that uniquely belongs to ClassC
    ...
}
h->someFunction();

If ClassB and ClassC have no common super class that implements someFunction, this is impossible*. The compiler needs to have some type information to be able to generate the code.

*) Ok, there is std::variant and std::any, but at this level, you are not doing yourself a favor if you start going down this path. There are other approaches (e.g., static polymorphism aka. templates), too, but again, those are reserved for more special cases.

Related