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

标签 c++ variant typename

我有以下函数模板,根据给定的typenameVARIANT返回特定类型的数据。

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

因此,由于我需要从 VARIANT 返回 unsigned int 类型,我尝试使用上面的函数,例如:

return VariantGetValue<unsigned int>(CV);

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

C2440 - 'return': cannot convert from 'BSTR' to 'unsigned int'

但是,如果我删除该行 if (S == "wchar_t* __ptr64") { return Variant.bstrVal; },编译器只给我以下警告:

C4715 - 'VariantGetValue': not all control paths return a value

我可以抑制此错误并继续吗?它安全吗?或者是否有其他方法可以在没有编译器错误的情况下执行此操作?

最佳答案

您不能根据代码在运行时采用的分支拥有多个返回类型。这里最好的选择是使用明确的特化。

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::getstd::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'
}

关于C++ 根据给定的类型名从 Variant 返回数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45205725/

相关文章:

c++ - 类函数与非类函数的名称冲突

delphi - 如何访问后期绑定(bind)的嵌套属性和方法?

c++ - 使用 typename::的模板结构特化

c++ - 如何将类型名称作为函数中的参数? (C++)

c++ - 为什么我需要在 g++ 中使用 typedef typename 而不是 VS?

c++ - Eclipse:C++静态库中的C代码,由C++库引用导致 undefined reference

c++ - 如何调用QCombobox的linedit的KeyPressEvent(QKeyEvent *)?

c++ - 从文件中删除特定行

c - 如果变体具有 INF 或 NAN 值,如何使变体的 ChangeType float ?

c++ - 如何编写一个输入和输出均为std::variant的函数