Home > Enterprise >  deferred selection of types during compile-time
deferred selection of types during compile-time

Time:05-30

Is there a standard way for me to select a type at compile-time in c 20 when the type depends on compile-time information available later in the function, i.e. the type is "deferred" because of intermediate compile-time dependencies.

For example something like this which depends on the auto keyword but does not compile:

template<bool value, typename ...>
struct bool_type : std::integral_constant<bool , value> {};

template<typename T>
void function(T* v) {
    auto r;
    bool different_type = false;
    if constexpr (...)
        r = (T)subfunc_a(v);
    else if constexpr (...)
        r = (T)subfunc_b(v);
    else if constexpr (...)
        r = (T)subfunc_c(v);
    else if constexpr (...);
        r = (T)subfunc_d(v);
    else if constexpr (...)
        r = (T)subfunc_e(v);
    // This condition depends on previous conditions. Extracting the condition
    // to the top of this function for use with `std::conditional` would be
    // burdensome. Decoupling the conditional in this way also risks errors. I
    // want to depend on the type system to enforce code correctness.
    else if constexpr (...) {
        r = (long)subfunc_f(v);
        different_type = true;
    }
    else if constexpr (...) {
        r = (unsigned long)subfunc_g(v);
        different_type = true;
    }
    else {
        static_assert(bool_type<false, T>::value, "Unsupported type");
    }
    do_common_work();
    if (different_type)
        do_more_work();
    *v = r;
}

Or this example which depends on the static if proposal which prevents if constexpr conditionals from creating a new scope. The proposal didn't pass so the code doesn't compile.

template<typename T>
void function(T* v) {
    bool different_type = false;
    if constexpr (...)
        T r = subfunc_a(v);
    else if constexpr (...)
        T r = subfunc_b(v);
    else if constexpr (...)
        T r = subfunc_c(v);
    else if constexpr (...);
        T r = subfunc_d(v);
    else if constexpr (...)
        T r = subfunc_e(v);
    else if constexpr (...) {
        different_type = true;
        long r = subfunc_f(v);
    }
    else if constexpr (...) {
        different_type = true;
        unsigned long r = subfunc_g(v);
    }
    else {
        static_assert(bool_type<false, T>::value, "Unsupported type");
    }
    do_common_work();
    if (different_type)
        do_more_work();
    *v = r;
}

CodePudding user response:

auto variable can only infer its type from the initialization expression in C . If you don't want to explicitly specify its type, you can extract the initialization into a separate function which returns the necessary value (type is auto) and initialize with this function's call.

In particular, the extracted function can be a lambda expression, so you get an immediately invoked function expression or IIFE:

#include <iostream>
#include <type_traits>

template <bool value, typename...>
struct bool_type : std::integral_constant<bool, value> {};

template <typename T> void function(T *v) {
    bool different_type = false;
    auto r = [&] {  // create a function
        if constexpr (std::is_same_v<T, int>) {
            return 10;
        } else if constexpr (std::is_same_v<T, double>) {
            return 10.0;
        } else if constexpr (std::is_same_v<T, long>) {
            different_type = true;
            return 10LL;
        } else {
            static_assert(bool_type<false, T>::value, "Unsupported type");
        }
    }();  // immediately invoke the created function
    std::cout << typeid(r).name() << " " << different_type << "\n";
    *v = r;
}

int main() {
    int a;
    double b;
    long c;
    [[maybe_unused]] float d;
    function(&a); // int 0
    function(&b); // double 0
    function(&c); // long long 1
    // function(&d);  // compilation error
}

In the code above, the lambda expression has a return type of auto, i.e. it's automatically deduced from the return chosen by if constexpr. Only a single return is chosen, so the return type is unambiguous, so r's type is also inferred correctly.

  • Related