如何使用可变参数模板转换每种变体类型

时间:2020-06-16 19:26:25

标签: c++ variadic-templates variant

我想做的是在从共享库中调用某些函数之前,将每个“ VariantType”(不同类型的联合)参数转换为它的类型。我到目前为止正在做的事情在下面。它只有3种不同的类型和2个参数,并且需要很多行。但是我想用7种不同类型的变元参数来实现这一点。这与可变参数模板有关(另一个相关的问题:Template tuple - calling a function on each element)。或者,如果您知道更好的方法,请告诉我。


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;
}

2 个答案:

答案 0 :(得分:3)

您有一个混乱且非常局部的运行时反射机制。我敢肯定您在使用这些东西时会感到很痛苦...所以首先要考虑的是:

  • 您真的需要这个吗?如果您可以避免这种情况并坚持编译时反射,那将使您的生活更轻松;或
  • C ++是您要使用的语言吗?如果您刚刚开始编程项目,并且这种运行时多态性对您至关重要,那么也许另一种语言(例如,解释语言?)可能更合适。

话虽如此-在许多情况下,您可以对C ++自己的变体类型感到满意:std::variant是在C ++ 17中引入的,它与std::visit一起使用,并且有模板访问者(如{ {3}}-但有两个模板。

这是下面的样子:

#include <variant>
#include <iostream>
#include <string>

int main() {
    using variant_type = std::variant<int, float, std::string>;
    variant_type v1{"hello world!"};
    variant_type v2{3.14f};

    std::visit([](auto&& x, auto&& y) { 
        // I used this as a stub:
        //
        //   std::cout << x << " , " << y << '\n';
        //
        // but you want:
        call(func_name, x, y);
    }, v1, v2);
}

this question

不过有一个警告-这不会从您的字符串中提取c_str()。如果您还想这样做,则可以执行以下两项操作之一:

  1. 首先在变体中存储const char*
  2. 您可以有一个模板化的转换器函数,而不是传递xy,该函数通常不执行任何操作,但将.c_str()用于常量字符串引用。

但是我真的不喜欢第二种方法。

答案 1 :(得分:0)

我终于找到了一种简单的方法,可以使用可变参数模板对每个参数进行强制转换(一定要重新发明轮子LRESULT CALLBACK DialogProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { // callback switch (msg) { case WM_CLOSE: DestroyWindow(hWnd); break; default: return DefWindowProcW(hWnd, msg, wp, lp); // Need to add `return` } } )。

std::visit
相关问题