UE4.20 compile fail on iOS
Hiya,
I'm trying the UE4 demo project using the Mac and iOS SDKs (v4.1.11.1)
I can build for Mac and everything runs fine. But when building to iOS, I get a compile fail error everywhere there's a conversion to FString. E.g. FString(joinedRoomName.cstr())
Note that this does not happen when using UE4.19. It only happens when using UE4.20 and building to iOS.
======================================
Here's one of the errors (they are all the same):
error: no matching conversion for functional-style cast from 'const EG_CHAR *' (aka 'const wchar_t *') to 'FString'
note: candidate constructor not viable: no known conversion from 'const EG_CHAR *' (aka 'const wchar_t *') to 'FString' for 1st argument
LogPlayLevel: FString(FString&&) = default;
note: candidate constructor not viable: no known conversion from 'const EG_CHAR *' (aka 'const wchar_t *') to 'const FString' for 1st argument
LogPlayLevel: FString(const FString&) = default;
note: candidate constructor not viable: no known conversion from 'const EG_CHAR *' (aka 'const wchar_t *') to 'const NSString *' for 1st argument
LogPlayLevel: FORCEINLINE FString(const NSString* In)
note: candidate template ignored: substitution failure [with CharType = wchar_t]: no type named 'Type' in 'TEnableIf'
LogPlayLevel: FORCEINLINE FString(const CharType* Src)
note: candidate constructor not viable: requires 0 arguments, but 1 was provided
LogPlayLevel: FString() = default;
note: candidate constructor not viable: requires 2 arguments, but 1 was provided
LogPlayLevel: FORCEINLINE FString(const FString& Other, int32 ExtraSlack)
note: candidate constructor not viable: requires 2 arguments, but 1 was provided
LogPlayLevel: FORCEINLINE FString(FString&& Other, int32 ExtraSlack)
note: candidate constructor not viable: requires 2 arguments, but 1 was provided
LogPlayLevel: FORCEINLINE explicit FString( int32 InCount, const TCHAR* InSrc )
I'm trying the UE4 demo project using the Mac and iOS SDKs (v4.1.11.1)
I can build for Mac and everything runs fine. But when building to iOS, I get a compile fail error everywhere there's a conversion to FString. E.g. FString(joinedRoomName.cstr())
Note that this does not happen when using UE4.19. It only happens when using UE4.20 and building to iOS.
======================================
Here's one of the errors (they are all the same):
error: no matching conversion for functional-style cast from 'const EG_CHAR *' (aka 'const wchar_t *') to 'FString'
note: candidate constructor not viable: no known conversion from 'const EG_CHAR *' (aka 'const wchar_t *') to 'FString' for 1st argument
LogPlayLevel: FString(FString&&) = default;
note: candidate constructor not viable: no known conversion from 'const EG_CHAR *' (aka 'const wchar_t *') to 'const FString' for 1st argument
LogPlayLevel: FString(const FString&) = default;
note: candidate constructor not viable: no known conversion from 'const EG_CHAR *' (aka 'const wchar_t *') to 'const NSString *' for 1st argument
LogPlayLevel: FORCEINLINE FString(const NSString* In)
note: candidate template ignored: substitution failure [with CharType = wchar_t]: no type named 'Type' in 'TEnableIf'
LogPlayLevel: FORCEINLINE FString(const CharType* Src)
note: candidate constructor not viable: requires 0 arguments, but 1 was provided
LogPlayLevel: FString() = default;
note: candidate constructor not viable: requires 2 arguments, but 1 was provided
LogPlayLevel: FORCEINLINE FString(const FString& Other, int32 ExtraSlack)
note: candidate constructor not viable: requires 2 arguments, but 1 was provided
LogPlayLevel: FORCEINLINE FString(FString&& Other, int32 ExtraSlack)
note: candidate constructor not viable: requires 2 arguments, but 1 was provided
LogPlayLevel: FORCEINLINE explicit FString( int32 InCount, const TCHAR* InSrc )
0
Best Answer
-
Hi @Kendo.
Please re-download the demo. I have just uploaded a new version with changes that address this issue.
Background info:
Unreals FString class internally stores its characters as c-array of TCHAR, while the Photon Clients JString class insternally stores its characters as c-array of EG_CHAR.
EG_CHAR is a define for wchar_t
Until 4.19, with UE default settings TCHAR was a typedef for wchar_t on all platforms.
In 4.20 they have changed it to be a typedef for char16_t on iOS and Android, but to remain a typedef for wchar_t on Windows and Mac (I have not checked for other platforms than the mentioned 4).
Hence starting with UE 4.20 on iOS and Android EG_CHAR and TCHAR are no longer effectively the same type. This means that simply passing the internal representation of a JString() to the constructor of a FString and vice versa does no longer work with these platforms. A simple pointer cast will not work either.
Instead an explicit encoding conversion is necessary.
However as the two string classes don't know of each other and neither the Photon Client nor Unreal provides any means of directly converting into the native format of the other ones string class, we need to use an intermediate format. Both, the Photon Client and Unreal Engine, provide converters from and to ANSI and from and to UTF8. However the conversion to ANSI would be lossy for non ASCII- characters. Hence UTF8 should be the intermediate encoding of choice.
The conversions FROM UTF8 encoded c-strings happen automatically when passing such c-strings to the constructors of JString and FString, but the conversions TO them needs to be done explicitly.
So instead ofFString(aJString.cstr())
you should writeFString(aJString.UTF8Representation().cstr())
and instead ofJString(*aFString)
you should writeJString(TCHAR_TO_UTF8((*aFString))
.
The demo source has already been updated accordingly, but I leave this information here so people know how to adjust their own code bases to this breaking change in Unreal Engine.5
Answers
-
Hi @Kendo.
Please re-download the demo. I have just uploaded a new version with changes that address this issue.
Background info:
Unreals FString class internally stores its characters as c-array of TCHAR, while the Photon Clients JString class insternally stores its characters as c-array of EG_CHAR.
EG_CHAR is a define for wchar_t
Until 4.19, with UE default settings TCHAR was a typedef for wchar_t on all platforms.
In 4.20 they have changed it to be a typedef for char16_t on iOS and Android, but to remain a typedef for wchar_t on Windows and Mac (I have not checked for other platforms than the mentioned 4).
Hence starting with UE 4.20 on iOS and Android EG_CHAR and TCHAR are no longer effectively the same type. This means that simply passing the internal representation of a JString() to the constructor of a FString and vice versa does no longer work with these platforms. A simple pointer cast will not work either.
Instead an explicit encoding conversion is necessary.
However as the two string classes don't know of each other and neither the Photon Client nor Unreal provides any means of directly converting into the native format of the other ones string class, we need to use an intermediate format. Both, the Photon Client and Unreal Engine, provide converters from and to ANSI and from and to UTF8. However the conversion to ANSI would be lossy for non ASCII- characters. Hence UTF8 should be the intermediate encoding of choice.
The conversions FROM UTF8 encoded c-strings happen automatically when passing such c-strings to the constructors of JString and FString, but the conversions TO them needs to be done explicitly.
So instead ofFString(aJString.cstr())
you should writeFString(aJString.UTF8Representation().cstr())
and instead ofJString(*aFString)
you should writeJString(TCHAR_TO_UTF8((*aFString))
.
The demo source has already been updated accordingly, but I leave this information here so people know how to adjust their own code bases to this breaking change in Unreal Engine.5 -
Thanks for the detailed response!
I had used FString::Printf(TEXT("%s"), aJString.cstr()) as a hacky workaround. But I'll get the updated demo as you suggested.
Thanks again.0