Search code examples
c++variadic-templatesvariant

How to cast each variant type with variadic template


What I want to do is to cast each "VariantType" (union of different types) argument to it's type before calling some function from a shared library. what I'm doing so far now is down below. it's just 3 different types and 2 arguments and it takes a lot lines. but I want to achieve this with variant number of argument with 7 different types. this has to do something with variadic template( another relevant question : Template tuple - calling a function on each element ). or if you know some better way let me know.


template<typename... T>
int call(const char* func_name, T... args) {
    // this will call func_name(args...) somehow from a dll binary.
    // If you need the implementation : https://hastebin.com/ocoyaniruj.cpp
}

int main(int argc, char** argv) {

    const char* func_name = "func_name";
    VariantType arg1 = "hello world!";
    VariantType arg2 = 3.14;

    if (arg1.get_type() == VariantType::INT) {
        if (arg2.get_type() == VariantType::INT) {
            call(func_name, (int)arg1, (int)arg2);
        } else if (arg2.get_type() == VariantType::FLOAT){
            call(func_name, (int)arg1, (float)arg2);
        } else if (arg1.get_type() == VariantType::STRING){
            call(func_name, (int)arg1, arg2.c_str());
        }

    } else if (arg1.get_type() == VariantType::FLOAT){
        if (arg2.get_type() == VariantType::INT) {
            call(func_name, (float)arg1, (int)arg2);
        } else if (arg2.get_type() == VariantType::FLOAT){
            call(func_name, (float)arg1, (float)arg2);
        } else if (arg1.get_type() == VariantType::STRING){
            call(func_name, (float)arg1, arg2.c_str());
        }

    } else if (arg1.get_type() == VariantType::STRING){
        if (arg2.get_type() == VariantType::INT) {
            call(func_name, arg1.c_str(), (int)arg2);
        } else if (arg2.get_type() == VariantType::FLOAT){
            call(func_name, arg1.c_str(), (float)arg2);
        } else if (arg1.get_type() == VariantType::STRING){
            call(func_name, arg1.c_str(), arg2.c_str());
        }
    }
    return 0;
}


Solution

  • I've finally found the simple way to cast each argument with a variadic template (kinda reinvent the wheel std::visit).

    template<typename... Targs>
    void visit(const char* func_name, int visiting_arg, VariantType front, Targs... p_args) {
    
        if (visiting_arg == 0) {
            call(func_name, p_args...);
            return;
        }
    
        if (front.get_type() == VariantType::INT) {
            visit(func_name, visiting_arg-1, p_args..., (int)front);
    
        } else if (front.get_type() == VariantType::FLOAT) {
            visit(func_name, visiting_arg - 1, p_args..., (float)front);
    
        } else if (front.get_type() == VariantType::STRING) {
            visit(func_name, visiting_arg - 1, p_args..., front.c_str());
    
        }
    
    }
    
    int main(int argc, char** argv) {
    
        const char* func_name = "func_name";
        int argcount = 3;
    
        VariantType s = "Hello world!";
        VariantType f = 3.14;
        VariantType i = 42;
    
        visit(func_name, argcount, s, f, i, VariantType("--placeholder--"));
    
        return 0;
    }