C ++根据给定的typename从Variant返回数据

时间:2017-07-20 05:16:11

标签: c++ variant typename

根据给定的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返回VARIANT类型时,我尝试使用上述功能,如:

return VariantGetValue<unsigned int>(CV);

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

  

C2440 - &#39;返回&#39;:无法转换为&#39; BSTR&#39;到&#39; unsigned int&#39;

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

  

C4715 - &#39; VariantGetValue&#39;:并非所有控制路径都返回值

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

1 个答案:

答案 0 :(得分:3)

根据代码在运行时要使用的分支,不能有多种返回类型。这里最好的选择是使用明确的专业化。

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