The following snippet results in a compile time error in xcode:
//snippet from header file
enum class EnumType
{
A, B, C, END_OF_LIST,
};
//later, inside the juce::VariantConverter<std::array<EnumType, ...>::fromVar(v) function:
std::array<Type, static_cast<size_t>(Type::END_OF_LIST)> arr1;
//v is the function argument of `juce::VariantConverter<>::fromVar()`
auto mb = *v.getBinaryData();
auto arr2 = juce::Array<EnumType>(mb.getData(), mb.getSize() / sizeof(EnumType) );
jassert( arr1.size() == arr2.size() );
for( size_t i = 0; i < arr1.size(); ++i )
{
arr1[i] = arr2[i]; ///<<<<<<<< ## ERROR: Arithmetic on a pointer to void
}
Discovered while trying to serialize an std::array<EnumType>
to/from juce::var
using juce::VariantConverter<>
The error is caused by this function, in juce::Array:
template <typename TypeToCreateFrom>
Array (const TypeToCreateFrom* data, int numValues)
{
values.addArray (data, numValues);
}
when mb.getData()
is not cast, TypeToCreateFrom
is deduced to be void*
, because that is what MemoryBlock::getData()
returns.
ArrayBase::addArray
also doesn’t cast:
template <typename Type>
void addArray (const Type* elementsToAdd, int numElementsToAdd)
{
ensureAllocatedSize (numUsed + numElementsToAdd);
addArrayInternal (elementsToAdd, numElementsToAdd);
numUsed += numElementsToAdd;
}
Type
is treated again as void*
.
Finally, addArrayInternal
also does not cast:
template <typename Type>
void addArrayInternal (const Type* otherElements, int numElements)
{
if constexpr (isTriviallyCopyable && std::is_same_v<Type, ElementType>)
{
if (numElements > 0)
memcpy (elements + numUsed, otherElements, (size_t) numElements * sizeof (ElementType));
}
else
{
auto* start = elements + numUsed;
while (--numElements >= 0)
new (start++) ElementType (*(otherElements++));
}
}
Type
is still void*
here.
I’m not sure if this is a bug in this particular constructor of juce::Array
, but the solution is to cast mb.getData()
to the type needed.