If the reason you don’t want to use the workaround is that you are sending a format string
, and you want to follow the FString with formated vairables. Then what you would need is:
FString FormattedErrorMessage;
if (ErrorMessage.Len() > 0)
{
int32 Size = snprintf(nullptr, 0, TCHAR_TO_UTF8(*ErrorMessage), \* your variables here*\) + 1;
char* Buffer = new char[Size];
snprintf(Buffer, Size, TCHAR_TO_UTF8(*ErrorMessage), \* your variables here*\);
FormattedErrorMessage = FString(UTF8_TO_TCHAR(Buffer));
delete[] Buffer;
}
UE_LOG(LogTemp, Error, TEXT("%s"), *FormattedErrorMessage);
This will also work with a variadic template if that’s what you are looking for. That’s how I stumbled on this thread.
in such chase just paste std::forward(args)… into * your variables here*
For example I used it to create myself a template that encapsulates Timeout checking and error loging into a single template call:
template<typename... Args>
static bool OnTimeout_helper(float MaxTime, FDateTime StartTime, const FString& ErrorMessage, Args&&... args)
{
if ((FDateTime::Now() - StartTime).GetTotalSeconds() <= MaxTime)
{
return false;
}
FString FormattedErrorMessage;
if (ErrorMessage.Len() > 0)
{
int32 Size = snprintf(nullptr, 0, TCHAR_TO_UTF8(*ErrorMessage), std::forward<Args>(args)...) + 1;
char* Buffer = new char[Size];
snprintf(Buffer, Size, TCHAR_TO_UTF8(*ErrorMessage), std::forward<Args>(args)...);
FormattedErrorMessage = FString(UTF8_TO_TCHAR(Buffer));
delete[] Buffer;
}
UE_LOG(LogTemp, Error, TEXT("%s"), *FormattedErrorMessage);
return true;
}