簡體   English   中英

如何使用可變參數模板轉換每種變體類型

[英]How to cast each variant type with variadic template

我想要做的是在從共享庫調用一些 function 之前將每個“VariantType”(不同類型的聯合)參數轉換為它的類型。 到目前為止,我正在做的事情在下面。 它只有 3 種不同的類型和 2 個 arguments 並且需要很多行。 但我想用 7 種不同類型的變體參數來實現這一點。 這與可變參數模板有關(另一個相關問題: 模板元組 - 在每個元素上調用 function )。 或者,如果您知道更好的方法,請告訴我。


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

你有一個混亂的、非常部分的運行時反射機制。 我敢肯定你對這些東西感到很痛苦......所以首先要考慮的是:

  • 你真的需要這個嗎? 如果您可以避免它並堅持編譯時反射,那將使您的生活更輕松; 或者
  • C++ 是您要使用的語言嗎? 如果您剛剛開始您的編程項目,並且這種運行時多態性對您來說至關重要,那么也許另一種語言(例如解釋語言?)可能更合適。

話雖如此 - 在許多情況下,您可以對 C++ 自己的變體類型感到滿意:在 C++17 中引入的std::variant以及std::visit和一個模板化的訪問者(如在這個問題中 - 但有兩個模板)。

這是它的樣子:

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

神螺栓

但是,有一個警告 - 這不會從您的字符串中提取c_str() 如果你也想這樣做,你可以做以下兩件事之一:

  1. 在變體中存儲一個const char*開始。
  2. 除了傳遞xy之外,您還可以使用模板化轉換器 function,它通常什么都不做,但將.c_str()應用於 const 字符串引用。

但我不太喜歡第二種方法。

我終於找到了使用可變參數模板強制轉換每個參數的簡單方法(有點重新發明輪子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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM