Skip to content

Instantly share code, notes, and snippets.

@hach-que
Created May 13, 2026 09:30
Show Gist options
  • Select an option

  • Save hach-que/c9ff4434f562973be8cf04ef18ccfc48 to your computer and use it in GitHub Desktop.

Select an option

Save hach-que/c9ff4434f562973be8cf04ef18ccfc48 to your computer and use it in GitHub Desktop.
C++20 header library for passing/concatenating Unreal Engine string literals as template arguments
template <TStringLiteral LiteralArg> class TTemplateWithStringLiteral
{
public:
consteval auto GetValue()
{
return LiteralArg;
}
};
using FInstantiatedTemplate = TTemplateWithStringLiteral<TEXT("Hello World")>;
void Test()
{
FInstantiatedTemplate HelloWorld;
auto Joined1 = JoinStringLiterals(
AsStringLiteral<TEXT("Before ")>(),
HelloWorld.GetValue(),
AsStringLiteral<TEXT(" After")>());
auto Joined2 = AsStringLiteral<TEXT("Before ")>() + HelloWorld.GetValue() + AsStringLiteral<TEXT(" After")>();
auto Joined3 = TEXT("Before ") + HelloWorld.GetValue() + TEXT(" After");
Joined1.Get(); // returns const TCHAR* of "Before Hello World After"
Joined2.Get(); // returns const TCHAR* of "Before Hello World After"
Joined3.Get(); // returns const TCHAR* of "Before Hello World After"
}
// You can also join inside consteval functions of the template with a TStringLiteral
template <TStringLiteral Test> class TMyTemplate
{
public:
static consteval auto ReturnWrappedValue()
{
return JoinStringLiterals(AsStringLiteral<TEXT("Before ")>(), Test, AsStringLiteral<TEXT(" After")>());
}
static consteval auto ReturnWrappedValue2()
{
return AsStringLiteral<TEXT("Before ")>() + Test + AsStringLiteral<TEXT(" After")>();
}
static consteval auto ReturnWrappedValue3()
{
return TEXT("Before ") + Test + TEXT(" After");
}
};
void Test2()
{
TMyTemplate<TEXT("Hello World")>::ReturnWrappedValue().Get(); // returns const TCHAR* of "Before Hello World After"
TMyTemplate<TEXT("Hello World")>::ReturnWrappedValue2().Get(); // returns const TCHAR* of "Before Hello World After"
TMyTemplate<TEXT("Hello World")>::ReturnWrappedValue3().Get(); // returns const TCHAR* of "Before Hello World After"
}
// Copyright June Rhodes. MIT Licensed.
template <size_t N> struct TStringLiteral
{
consteval TStringLiteral(const TCHAR (&InValue)[N])
{
std::copy_n(InValue, N, Value);
}
consteval TStringLiteral()
{
}
static constexpr size_t Size = N;
TCHAR Value[N];
constexpr const TCHAR *Get()
{
return &Value[0];
}
};
template <size_t N> TStringLiteral(const TCHAR (&InValue)[N]) -> TStringLiteral<N>;
template <TStringLiteral L> consteval auto AsStringLiteral()
{
return L;
}
template <size_t... N> consteval auto JoinStringLiterals(TStringLiteral<N>... Values);
template <size_t A, size_t B, size_t... N>
consteval auto JoinStringLiterals(TStringLiteral<A> ValueA, TStringLiteral<B> ValueB, TStringLiteral<N>... Other)
{
TStringLiteral<(A - 1 + B)> Result;
std::copy_n(&ValueA.Value[0], ValueA.Size, &Result.Value[0]);
std::copy_n(&ValueB.Value[0], ValueB.Size, &Result.Value[ValueA.Size - 1]);
return JoinStringLiterals(Result, Other...);
}
template <size_t A> consteval auto JoinStringLiterals(TStringLiteral<A> Value)
{
return Value;
}
template <size_t A, size_t B> consteval auto operator+(TStringLiteral<A> ValueA, TStringLiteral<B> ValueB)
{
return JoinStringLiterals(ValueA, ValueB);
}
template <size_t A, size_t B> consteval auto operator+(const TCHAR (&ValueA)[A], TStringLiteral<B> ValueB)
{
return JoinStringLiterals(TStringLiteral<A>(ValueA), ValueB);
}
template <size_t A, size_t B> consteval auto operator+(TStringLiteral<A> ValueA, const TCHAR (&ValueB)[B])
{
return JoinStringLiterals(ValueA, TStringLiteral<B>(ValueB));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment