I’m currently trying to make a set of conversion functions which, through one call, can (attempt to) convert a JavaScript object (CefV8Value) into its C++ counterpart, with support for pointers.
Here are the conversion functions (pointer conversion at the end):
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;
}
And here’s the code that is using said pointer function:
WrapClass *pThis = convert_v8value_to_cpp<WrapClass*>(object);
Visual Studio complains that:
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
]
I don’t understand how the call is ambiguous (other than WrapClass * matches the first conversion function of T). However it also says that a possible call candidate is the std::vector conversion. How is this possible?
Many thanks in advance!
Both of these:
are not function partial specialisations (which are not allowed anyway), but overloads, so together with the primary function template they’re all three ambiguous, because they only differ from each other in the return type.
You want your function template
convert_v8value_to_cppto delegate to a static function (do_it(), say) in a class templateconvert_v8value_to_cpp_helper, because unlike function templates class templates can be specialised.Primary class template:
Full specialisations:
Specialisation for
std::vector(incl. those with a custom allocator):And, finally, the specialisation for pointers:
These are now used in the real function template:
There’s no more ambiguity because there’s only one function template (but there might be ambiguity if partial template specialisation ordering fails to find a single best match, but that shouldn’t be the case here).