我有以下函数模板根据给定的typename
从VARIANT
返回特定类型的数据。
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 - "返回":无法从"BSTR"转换为"无符号整数">
但是,如果我删除if (S == "wchar_t* __ptr64") { return Variant.bstrVal; }
行,编译器只会给我以下警告:
C4715 - "VariantGetValue":并非所有控制路径都返回值
我可以抑制此错误并继续吗?它是否安全,或者是否有任何其他方法可以在没有编译器错误的情况下执行此操作?
不能基于代码在运行时将采用的分支具有多个返回类型。 这里最好的选择是使用明确的专业化。
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'
}