我正在尝试创建一组转换函数,通过一次调用,可以(尝试)将JavaScript对象(CefV8Value
)转换为其C ++对应函数,并支持指针。
以下是转换函数(结尾处的指针转换):
template<typename T>
T convert_v8value_to_cpp(const CefRefPtr<CefV8Value> &value) {};
// Explicit type conversion functions
#define V8VALUE_TO_CPP_CONVERSION(type) \
template<> type \
convert_v8value_to_cpp<type>(const CefRefPtr<CefV8Value> &value)
V8VALUE_TO_CPP_CONVERSION(CefRefPtr<CefV8Value>)
{
return value;
}
V8VALUE_TO_CPP_CONVERSION(bool)
{
return value->GetBoolValue();
}
V8VALUE_TO_CPP_CONVERSION(int)
{
return value->GetIntValue();
}
V8VALUE_TO_CPP_CONVERSION(std::string)
{
return value->GetStringValue().ToString();
}
V8VALUE_TO_CPP_CONVERSION(const char *)
{
return value->GetStringValue().ToString().c_str();
}
V8VALUE_TO_CPP_CONVERSION(std::wstring)
{
return value->GetStringValue().ToWString();
}
// HACKHACK: most VGUI functions take non-const wchar_t pointers, when they
// shouldn't
V8VALUE_TO_CPP_CONVERSION(wchar_t *)
{
return (wchar_t*)value->GetStringValue().ToWString().c_str();
}
V8VALUE_TO_CPP_CONVERSION(const wchar_t *)
{
return value->GetStringValue().ToWString().c_str();
}
V8VALUE_TO_CPP_CONVERSION(double)
{
return value->GetDoubleValue();
}
V8VALUE_TO_CPP_CONVERSION(float)
{
return value->GetDoubleValue();
}
//-----------------------------------------------------------------------------
// Purpose: converts a JS array to a C++ vector (of type T)
//-----------------------------------------------------------------------------
template<typename T>
std::vector<T> convert_v8value_to_cpp(const CefRefPtr<CefV8Value> &value)
{
std::vector<T> vec;
if(!value->IsArray())
return vec;
for(int i = 0; i < value->GetArrayLength(); ++i)
{
CefRefPtr<CefV8Value> element = value->GetValue(i);
vec.push_back(convert_v8value_to_cpp<T>(element));
}
return vec; // hopefully move semantics will optimise this and not copy-construct
}
//-----------------------------------------------------------------------------
// Purpose: converts a JS object to a C++ pointer (where T is a pointer type)
//-----------------------------------------------------------------------------
template<typename T>
typename std::enable_if<std::is_pointer<T>::value, T>::type
convert_v8value_to_cpp(const CefRefPtr<CefV8Value> &value)
{
if(!value->IsObject())
return NULL;
CefRefPtr<CefV8Value> pTypeId = value->GetValue("__v8bind_typeid__");
if(!pTypeId || !pTypeId->IsString())
return NULL;
CefRefPtr<CefV8Value> pPointerVal = value->GetValue("__v8bind_ptr__");
if(!pPointerVal || !pPointerVal->IsInt())
return NULL;
if(pTypeId->GetStringValue().ToString() == typeid(T).name())
return (T)pPointerVal->GetIntValue();
return NULL;
}
这是使用所述指针函数的代码:
WrapClass *pThis = convert_v8value_to_cpp<WrapClass*>(object);
Visual Studio 抱怨说:
error C2668: 'convert_v8value_to_cpp' : ambiguous call to overloaded function
binding_test.cpp(106): could be 'Point *convert_v8value_to_cpp<WrapClass*>(const CefRefPtr<T> &)'
with
[
WrapClass=Point,
T=CefV8Value
]
binding_test.cpp(88): or 'std::vector<_Ty,_Ax> convert_v8value_to_cpp<WrapClass*>(const CefRefPtr<T> &)'
with
[
_Ty=Point *,
_Ax=std::allocator<Point *>,
WrapClass=Point,
T=CefV8Value
]
binding_test.cpp(31): or 'T convert_v8value_to_cpp<WrapClass*>(const CefRefPtr<CefV8Value> &)'
with
[
T=Point *,
WrapClass=Point
]
while trying to match the argument list '(CefRefPtr<T>)'
with
[
T=CefV8Value
]
我不明白该调用是多么模糊(除了WrapClass *
与T
的第一个转换函数匹配)。但是它也说可能的呼叫候选者是std::vector
转换。这怎么可能?
非常感谢提前!
答案 0 :(得分:6)
这两个:
template<typename T>
std::vector<T> convert_v8value_to_cpp(const CefRefPtr<CefV8Value> &value)
{ ... }
template<typename T>
typename std::enable_if<std::is_pointer<T>::value, T>::type
convert_v8value_to_cpp(const CefRefPtr<CefV8Value> &value)
{ ... }
不是函数部分特化(无论如何都不允许),但是重载,所以与主函数模板一起,它们都是三个不明确的,因为它们在返回类型中只是彼此不同。
您希望函数模板convert_v8value_to_cpp
委托给类模板do_it()
中的静态函数(例如convert_v8value_to_cpp_helper
),因为与函数模板不同,类模板可以他们是专门的。
小学班级模板:
template <typename T>
struct convert_v8value_to_cpp_helper {}; // no do_it() here by intention
完全专业化:
// Explicit type conversion functions
#define V8VALUE_TO_CPP_CONVERSION(type, code) \
template <> struct convert_v8value_to_cpp_helper< type > { \
static T do_it() code \
}
V8VALUE_TO_CPP_CONVERSION(bool, {return value->GetBoolValue();});
V8VALUE_TO_CPP_CONVERSION(int, {return value->GetIntValue(); });
V8VALUE_TO_CPP_CONVERSION(std::string,
{ return value->GetStringValue().ToString(); });
V8VALUE_TO_CPP_CONVERSION(const char *,
{ return value->GetStringValue().ToString().c_str(); });
V8VALUE_TO_CPP_CONVERSION(std::wstring,
{ return value->GetStringValue().ToWString(); });
// HACKHACK: most VGUI functions take non-const wchar_t pointers, when they
// shouldn't
V8VALUE_TO_CPP_CONVERSION(wchar_t *,
{ return (wchar_t*)value->GetStringValue().ToWString().c_str(); });
V8VALUE_TO_CPP_CONVERSION(const wchar_t *,
{ return value->GetStringValue().ToWString().c_str(); });
V8VALUE_TO_CPP_CONVERSION(double, {return value->GetDoubleValue();});
V8VALUE_TO_CPP_CONVERSION(float, {return value->GetDoubleValue();});
std::vector
的专业化(包括具有自定义分配器的专业化):
template<typename T, typename A>
struct convert_v8value_to_cpp< std::vector<T,A> > {
static std::vector<T,A> do_it(const CefRefPtr<CefV8Value> &value)
{
std::vector<T,A> vec;
if (!value->IsArray())
return vec;
for(int i = 0; i < value->GetArrayLength(); ++i)
{
CefRefPtr<CefV8Value> element = value->GetValue(i);
vec.push_back(convert_v8value_to_cpp<T>(element));
}
return vec; // return value optimisation will kick in here
}
};
最后,指针的专业化:
template<typename T>
struct convert_v8value_to_cpp<T*> { // no need for enable_if
static T* do_it(const CefRefPtr<CefV8Value> &value)
{
if (!value->IsObject())
return nullptr; // don't use NULL in C++
CefRefPtr<CefV8Value> pTypeId = value->GetValue("__v8bind_typeid__");
if (!pTypeId || !pTypeId->IsString())
return nullptr;
CefRefPtr<CefV8Value> pPointerVal = value->GetValue("__v8bind_ptr__");
if (!pPointerVal || !pPointerVal->IsInt())
return nullptr;
if (pTypeId->GetStringValue().ToString() == typeid(T).name())
return (T*)pPointerVal->GetIntValue();
return nullptr;
}
};
现在在真实的功能模板中使用它们:
template <typename T>
T convert_v8value_to_cpp(const CefRefPtr<CefV8Value> &value)
{ return convert_v8value_to_cpp_helper<T>::do_it(value); }
没有更多的歧义,因为只有一个函数模板(但如果部分模板特化排序无法找到单个最佳匹配,则可能存在歧义,但这不应该是这种情况。)
答案 1 :(得分:2)
mmutz解释为什么它不明确(你有三个重载采用完全相同的参数类型,可以全部匹配convert_v8value_to_cpp<WrapClass*>
)
编辑:我看到mmutz现在也添加了一个解决方案,类似于我的下面。我发现阅读完全写得更容易,宏不会让我更容易阅读,甚至不会节省太多打字。
如果要部分专门化模板,则需要使用类:
template<typename T>
struct Converter;
template<>
struct Converter<bool>
{
typedef bool result_type;
static result_type convert(const CefRefPtr<CefV8Value> &value)
{ ... }
};
template<typename T>
struct Converter<std::vector<T>>
{
typedef std::vector<T> result_type;
static result_type convert(const CefRefPtr<CefV8Value> &value)
{ ... }
};
template<typename T>
struct Converter<T*>
{
typedef T* result_type;
static result_type convert(const CefRefPtr<CefV8Value> &value)
{ ... }
};
template<typename T>
typename Converter<T>::result_type
convert_v8value_to_cpp(const CefRefPtr<CefV8Value> &value)
{ return Converter<T>::convert(value); }