// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/UnrealString.h" #include "Misc/StringBuilder.h" #include "UObject/NameTypes.h" #include #include namespace CQTestConvert { using PrintStream = FStringBuilderBase; } namespace { template struct THasToString : std::false_type { }; template struct THasToString().ToString())>> : std::is_same().ToString())>::type { }; template class THasOStream { template (), std::declval()))> static std::true_type test(int); template static std::false_type test(...); public: static constexpr bool value = decltype(test(0))::value; }; static_assert(std::is_same().ToString())>::value); static_assert(THasOStream::value, "int should have an OStream operator"); static_assert(THasOStream::value, "int32 should have an OStream operator"); struct StructWithToString { FString ToString() { return FString(); } }; struct StructWithConstToString { FString ToString() const { return FString(); } }; static_assert(THasToString::value, "Struct with ToString should have ToString"); static_assert(THasToString::value, "Struct with ToString const should have ToString"); struct StructWithToStringWrongReturnType { int ToString() { return 42; } }; static_assert(!THasToString::value, "Struct with wrong return type on ToString should not have ToString"); struct SomeTestStruct { }; static_assert(!THasToString::value, "Struct without ToString should not have ToString"); static_assert(!THasOStream::value, "Struct without OStream operator should not have OStream"); } // namespace namespace CQTestConvert { template inline FString ToString(const T& Input) { if constexpr (THasToString::value) { return Input.ToString(); } else if constexpr (THasOStream::value) { PrintStream stream; stream << Input; return stream.ToString(); } else if constexpr (std::is_floating_point_v) { // Fallback for floating point type return FString::Printf(TEXT("%f"), Input); } else if constexpr (std::is_enum_v) { // Fallback for enum type return ToString(static_cast>(Input)); } else { ensureMsgf(false, TEXT("Did not find ToString, ostream operator, or CQTestConvert::ToString template specialization for provided type. Cast provided type to something else, or see CqTestConvertTests.cpp for examples")); return TEXT("value"); } } template <> inline FString ToString(const FString& Input) { return Input; } template inline FString ToString(const TArray& Input) { FString result = FString::JoinBy(Input, TEXT(", "), [](const TElement& e) { return CQTestConvert::ToString(e); }); return TEXT("[") + result + TEXT("]"); } template inline FString ToString(const TSet& Input) { FString result = FString::JoinBy(Input, TEXT(", "), [](const TElement& e) { return CQTestConvert::ToString(e); }); return TEXT("[") + result + TEXT("]"); } template inline FString ToString(const TMap& Input) { return FString::JoinBy(Input, TEXT(", "), [](const auto& kvp) { return TEXT("{") + CQTestConvert::ToString(kvp.Key) + TEXT(":") + CQTestConvert::ToString(kvp.Value) + TEXT("}"); }); } }