C++ Return 根据给定类型名从 Variant 获取数据
C++ Return data from a Variant according to the given typename
根据给定的 typename
.
,我有以下功能模板 return 来自 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; }
}
所以,因为我需要 return 来自 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
我可以抑制这个错误并继续吗?它是否安全,或者是否有任何其他方法可以在没有编译器错误的情况下执行此操作?
基于代码将在运行时采用的分支,您不能有多个 return 类型。这里最好的选择是使用显式专业化。
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'
}
根据给定的 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; }
}
所以,因为我需要 return 来自 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
我可以抑制这个错误并继续吗?它是否安全,或者是否有任何其他方法可以在没有编译器错误的情况下执行此操作?
基于代码将在运行时采用的分支,您不能有多个 return 类型。这里最好的选择是使用显式专业化。
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'
}