代码之家  ›  专栏  ›  技术社区  ›  GTAVLover

C++根据给定的类型名从变量返回数据

  •  2
  • GTAVLover  · 技术社区  · 8 年前

    我使用以下函数模板从 VARIANT typename .

    template <typename T>
    T VariantGetValue(VARIANT Variant) {
    
        std::string S(typeid(T).name());
    
        if (S == "wchar_t* __ptr64") { return Variant.bstrVal; }
        if (S == "unsigned int") { return Variant.uintVal; }
    }
    

    所以,当我需要返回一个 unsigned int 从a键入 变体

    return VariantGetValue<unsigned int>(CV);
    

    但不幸的是,编译器似乎忽略了 if (S == "....) 案例并给出错误:

    C2440-“return”:无法从“BSTR”转换为“unsigned int”

    但是,如果我去掉这条线 if (S == "wchar_t* __ptr64") { return Variant.bstrVal; }

    我可以抑制此错误并继续吗?这样做安全吗?或者有没有其他方法可以避免编译器错误?

    1 回复  |  直到 8 年前
        1
  •  3
  •   Henri Menke    8 年前

    基于代码在运行时将采用的分支,不能有多个返回类型。在这里,您最好使用显式专业化。

    template < typename T >
    T VariantGetValue(VARIANT) = delete;
    
    template <>
    unsigned int VariantGetValue<unsigned int>(VARIANT Variant)
    {
        VARIANT var;
        InitVariantFromUInt32(unsigned int{}, &var);
    
        if (Variant.vt != var.vt)
            throw std::runtime_error("bad get");
        return Variant.uintVal;
    }
    
    template <>
    BSTR VariantGetValue<BSTR>(VARIANT Variant)
    {
        if (/* check that Variant stores wchar_t* __ptr64 */)
            throw std::runtime_error("bad get");
        return Variant.bstrVal;
    }
    

    std::get 适用于 std::variant

    #include <iostream>
    #include <variant>
    
    using Variant = std::variant<int,std::string>;
    
    int main()
    {
        Variant v(13);
    
        std::cout << std::get<int>(v) << '\n'; // 13
      //std::cout << std::get<std::string>(v) << '\n'; // std::bad_variant_access
    }
    

    我已经实现了一个完整的示例,或许可以澄清评论中提出的一些问题。

    #include <iostream>
    #include <stdlib.h>
    #include <string.h>
    
    // Implement a mock VARIANT, don't take this code too seriously
    
    typedef unsigned int VARTYPE;
    typedef char* BSTR;
    enum { VT_UI4, VT_BSTR };
    
    struct VARIANT
    {
        VARIANT() : bstrVal(nullptr) {}
        VARTYPE vt;
        union {
            unsigned int uintVal;
            BSTR bstrVal;
        };
    };
    
    void InitVariantFromUInt32(unsigned int u, VARIANT * v)
    {
        v->vt = VT_UI4;
        v->uintVal = u;
    }
    
    void InitVariantFromString(char const * s, VARIANT * v)
    {
        v->vt = VT_BSTR;
        delete[] v->bstrVal;
        v->bstrVal = new char[strlen(s)];
        strcpy(v->bstrVal, s);
    }
    
    // VARIANT get value functions
    
    template < typename T >
    T VariantGetValue(VARIANT) = delete;
    
    template <>
    unsigned int VariantGetValue<unsigned int>(VARIANT Variant)
    {
        if (Variant.vt != VT_UI4)
            throw std::runtime_error("bad get");
        return Variant.uintVal;
    }
    
    template <>
    BSTR VariantGetValue<BSTR>(VARIANT Variant)
    {
        if (Variant.vt != VT_BSTR)
            throw std::runtime_error("bad get");
        return Variant.bstrVal;
    }
    
    int main()
    {
        VARIANT v;
        InitVariantFromUInt32(14, &v);
    
        std::cout << VariantGetValue<unsigned int>(v) << '\n';
        try {
            std::cout << VariantGetValue<BSTR>(v) << '\n';
        } catch (std::exception const& e) {
            std::cout << "Get failed!" << '\n';
        }
    
        VARIANT w;
        InitVariantFromString("Hello World!", &w);
    
        std::cout << VariantGetValue<BSTR>(w) << '\n';
    
      //std::cout << VariantGetValue<bool>(w) << '\n'; // error: call to deleted function 'VariantGetValue'
    }