【问题标题】:How to cast each variant type with variadic template如何使用可变参数模板转换每种变体类型
【发布时间】:2020-06-16 19:26:25
【问题描述】:

我想要做的是在从共享库调用某些函数之前将每个“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;
}

【问题讨论】:

  • 这似乎是在同时重新发明两个轮子。第一个轮子称为std::variant。第二个轮子称为std::visit。显示的代码都不是必需的,std::variantstd::visit
  • 或者如果您真的不能使用 C++17,请使用旧 C++ 版本的 Boost 版本
  • @SamVarshavchik 我会看看他们。非常感谢。
  • @underscore_d boost 变体是否适用于 std::visit ?
  • 这个问题不成立。如果你可以使用std::visit,你可以使用std::variant,如果你可以使用标准库版本而不是第三方库,你应该使用。所以,如果你可以使用任何一个,你应该同时使用,不需要混合和匹配

标签: c++ variadic-templates variant


【解决方案1】:

你有一个混乱的,非常部分的运行时反射机制。我敢肯定你对这些东西感到很痛苦......所以首先要考虑的是:

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

话虽如此 - 在许多情况下,您可以对 C++ 自己的变体类型感到满意:在 C++17 中引入的std::variant,以及 std::visit 和模板化访问者(如 this question - 但是有两个模板)。

这就是它的样子:

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

GodBolt

但有一个警告 - 这不会从您的字符串中提取 c_str()。如果你也想这样做,你可以做以下两件事之一:

  1. 在变体中存储 const char* 以作为开头。
  2. 除了传递 xy 之外,您还可以使用模板化的转换器函数,该函数通常什么都不做,但将 .c_str() 应用于 const 字符串引用。

但我不太喜欢第二种方法。

【讨论】:

    【解决方案2】:

    我终于找到了使用可变参数模板强制转换每个参数的简单方法(有点重新发明轮子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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-26
      • 2019-09-01
      • 2011-07-11
      • 2023-04-02
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多