Search code examples
c++c++20type-traits

Conditionally declare a variable of a certain type


Here is what I want to achieve:

struct A { A(/* ... */) {} A(A const&) = delete; };
struct B { B(/* ... */) {} B(B const&) = delete; };

int main()
{
    static bool constexpr cond = false;

    [[maybe_unused]]
    A a(/* ... */);
    [[maybe_unused]]
    B b(/* ... */);

    std::conditional_t<cond, A, B> c = cond ? a : b;

    return 0;
}

This doesn't compile, since the "?" operator requires both types to be convertible to each other. What I (obviously) need is that c is a or b depending on wheter cond is true or false. How can I achieve that?


Solution

  • Something which technically works, but isn't very pretty:

    auto& c = [&] -> auto& {
        if constexpr (cond) return a;
        else                return b;
    }();
    
    // rest of function ...
    

    This relies on if constexpr being able to influence the deduced return type of this lambda expression. Therefore, it also relies on cond being a constant expression.

    However, it is pretty rare that you would have to do this. Usually, you would write a function template which works with either A or B and then pass in the appropriate object.

    // f could also be a separate function
    auto f = [&](auto& c) {
        // rest of function ...
    };
    
    // this uses "if constexpr", but would work with a regular if statement too
    if constexpr (cond) f(a);
    else                f(b);