FString::Printf problem with fmt arg

In version 4.20 the FString::Printf generates a warning

FString::Printf((Value > 0) ? TEXT("+%.*f") : TEXT("%.*f"), precision, Value)

warning C4996: ‘FString::Printf’: The formatting string must now be a TCHAR string literal. Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.

but If I write

if (Value > 0)
     FString::Printf(TEXT("+%.*f"), precision, Value);
else
     FString::Printf(TEXT("%.*f"), precision, Value);

No more warning.

Hey,

I have not tried that code, but I see a potential problem in your first implementation with the ternary operator. If that evaluates to true the first TEXT macro is not going to receive the arguments and I believe that is what you are seeing. Hope that helps

In C++ the first and the second implementation are producing the same result.
In 4.19.2 it works. But since Printf changed in 4.20, and it produces a warning and should not work in future release.

What I do not understand, why with a ternary operator it does generates a warning, since the result should be the same.

I’m wondering the exact same thing.

The implementation that generates a warning is the one where the type comparison in the template fails when looking for an array or ref of TCHAR.

template <typename FmtType, typename... Types>
	DEPRECATED(4.20, "The formatting string must now be a TCHAR string literal.")
	static typename TEnableIf<!TIsArrayOrRefOfType<FmtType, TCHAR>::Value, FString>::Type Printf(const FmtType& Fmt, Types... Args)

How would a ternary operator change the output enough for that to return false?
I just did some research and it seems to only change the output type when two different types are used. Not the case here, though.

This isn’t an answer, but I’d love to hear from Epic why they made this change in 4.20. This FString::Printf warning indicates they plan on breaking API compatibility/similarity with sprintf-style formatting, where you may want to pass a TCHAR variable into the formatting string as opposed to a TCHAR string literal, and I can’t see an obvious replacement, which seems like a pretty crappy move. I assume it was done for optimisation, but I’d appreciate a workaround as there are plenty of legitimate use cases for wanting to pass in a TCHAR varaible as opposed to a string literal that’s known at compile time. For example, if you wanted a function that outputs a formatted float based on a passed-in
string format, which may be “%0.1f” or “%.3f” (or many other possibilities), how do we do this from 4.21 onwards the “Epic” way?

A ternary operator is evaluated at runtime, so it’s not a literal string known at compile time. So it generates the warning.

I don’t think it has something to do with the ternary operator.

I write this

		TCHAR* s = nullptr; 
		if (Value > 0)
			s = TEXT("+%.*f");
		else
			s = TEXT("%.*f");
		FString t = FString::Printf(s, precision, Value);

and exactly the same warning

Exactly, ternary operator is not the problem. Now they want a literal(a string hardcoded in the code) and there’s no way to escape this other than use other functions with similar behaviours. Eg. FText:Format

In fact the code must be written as follow:

(Value > 0) ? FString::Printf(TEXT("+%.*f"), precision, Value) : FString::Printf(TEXT("%.*f"), precision, Value)

instead of

FString::Printf((Value > 0) ? TEXT("+%.*f") : TEXT("%.*f"), precision, Value)