Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 std::conditional at runtime?

I'm looking to do something like this:

void func(void *data, const int dtype)
{
    typedef typename std::conditional<dtype==0,float,double>::type DataType;

    funcT((DataType *)data);

    return;
}

This will not compile because dtype needs to be known at compile time. I'm trying to avoid using a switch statement, because I have 8 data types I am working with, with many functions such as the one above, being called from Python via ctypes.

Is there a way something like std::conditional can done during run time, making use of the dtype identifier passed in?

like image 491
wolfblade87 Avatar asked Jul 29 '26 03:07

wolfblade87


2 Answers

All types must be resolved at compile time. So no type, can ever depend on a runtime parameter to a function. The way to handle something like this is basically to build a visiting mechanism, once, and then you can reuse it. Basically, something like this:

template <class F>
void visit_data(void* data, const int dtype, F f) {
    switch (dtype)
    case 0: f(*static_cast<float*>(data));
    case 1: f(*static_cast<double*>(data));
}

Now you can implement functions by writing visitors:

struct func_impl {
    void operator()(float&) { ... }
    void operator()(double&) { ... }
};

Your visitor can also use generic code:

struct func_impl2 {
    template <class T>
    void operator()(T&) { ... }
};

Then you can write your function by leveraging the visitor:

void func(void* data, const int dtype) {
    visit_data(data, dtype, func_impl{});
}

The switch case over your list of types will only appear once in your entire codebase. If you add a new type, any visitor that doesn't handle it will give a compile time error if used.

You can also use lambdas to do it inline with a helper function or two; especially useful in 14 where you have generic lambdas.

like image 78
Nir Friedman Avatar answered Jul 30 '26 18:07

Nir Friedman


If you can use C++17 it can be solved with a std::visitor and std::variant like so:

using var_t = std::variant<float, double>;
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

void func(var_t arg) {
    std::visit(overloaded {
            [](float  arg) { foo_float(arg); },
            [](double arg) { foo_double(arg); },
    }, arg);
}
like image 39
aerkenemesis Avatar answered Jul 30 '26 17:07

aerkenemesis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!