feat(templates): add TFunction and the corresponding testing
This commit is contained in:
		@@ -22,6 +22,7 @@ void TestTemplates()
 | 
			
		||||
	TestVariant();
 | 
			
		||||
	TestAny();
 | 
			
		||||
	TestTuple();
 | 
			
		||||
	TestFunction();
 | 
			
		||||
	TestMiscTemplates();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -532,107 +533,107 @@ void TestAny()
 | 
			
		||||
 | 
			
		||||
void TestTuple()
 | 
			
		||||
{
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int32, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int32, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int32, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int32, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int32, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int32, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int32, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int32, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int, char>&&>().GetValue<0>()),                int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int, char>&&>().GetValue<0>()), const          int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int, char>&&>().GetValue<0>()),       volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int, char>&&>().GetValue<0>()), const          int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int, char>&&>().GetValue<0>()), const          int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int, char>&&>().GetValue<0>()),       volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int, char>&&>().GetValue<0>()),       volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int32, char>&&>().GetValue<0>()),                int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int32, char>&&>().GetValue<0>()), const          int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int32, char>&&>().GetValue<0>()),       volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int32, char>&&>().GetValue<0>()), const          int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int32, char>&&>().GetValue<0>()), const          int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int32, char>&&>().GetValue<0>()),       volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int32, char>&&>().GetValue<0>()),       volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int32, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int32&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int32&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int32&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int32&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int32&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int32&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int32&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int32&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int32&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int32&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int32&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int32&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int32&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int&, char>&&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int&, char>&&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int&, char>&&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int&, char>&&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int&, char>&&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int&, char>&&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int&, char>&&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int&, char>&&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int&, char>&&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int&, char>&&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int&, char>&&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int&, char>&&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int&, char>&&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int&, char>&&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int&, char>&&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int&, char>&&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int32&, char>&&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int32&, char>&&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int32&, char>&&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int32&, char>&&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int32&, char>&&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int32&, char>&&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int32&, char>&&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int32&, char>&&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int32&, char>&&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int32&, char>&&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int32&, char>&&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int32&, char>&&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int32&, char>&&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int&&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int&&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int&&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int&&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int&&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int&&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int&&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int&&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int&&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int&&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int&&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int&&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int&&, char>&>().GetValue<0>()),                int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int&&, char>&>().GetValue<0>()), const          int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int&&, char>&>().GetValue<0>()),       volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int&&, char>&>().GetValue<0>()), const volatile int&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int32&&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int32&&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int32&&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int32&&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int32&&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int32&&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int32&&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int32&&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int32&&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int32&&, char>&>().GetValue<0>()),                int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int32&&, char>&>().GetValue<0>()), const          int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int32&&, char>&>().GetValue<0>()),       volatile int32&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int32&&, char>&>().GetValue<0>()), const volatile int32&>::Value));
 | 
			
		||||
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int&&, char>&&>().GetValue<0>()),                int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int&&, char>&&>().GetValue<0>()), const          int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int&&, char>&&>().GetValue<0>()),       volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int&&, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int&&, char>&&>().GetValue<0>()),                int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int&&, char>&&>().GetValue<0>()), const          int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int&&, char>&&>().GetValue<0>()),       volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int&&, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int&&, char>&&>().GetValue<0>()),                int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int&&, char>&&>().GetValue<0>()), const          int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int&&, char>&&>().GetValue<0>()),       volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int&&, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int&&, char>&&>().GetValue<0>()),                int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int&&, char>&&>().GetValue<0>()), const          int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int&&, char>&&>().GetValue<0>()),       volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int&&, char>&&>().GetValue<0>()), const volatile int&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<               int32&&, char>&&>().GetValue<0>()),                int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const          int32&&, char>&&>().GetValue<0>()), const          int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<      volatile int32&&, char>&&>().GetValue<0>()),       volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<               TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<               int32&&, char>&&>().GetValue<0>()),                int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const          int32&&, char>&&>().GetValue<0>()), const          int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<      volatile int32&&, char>&&>().GetValue<0>()),       volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const          TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<               int32&&, char>&&>().GetValue<0>()),                int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const          int32&&, char>&&>().GetValue<0>()), const          int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<      volatile int32&&, char>&&>().GetValue<0>()),       volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<      volatile TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<               int32&&, char>&&>().GetValue<0>()),                int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const          int32&&, char>&&>().GetValue<0>()), const          int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<      volatile int32&&, char>&&>().GetValue<0>()),       volatile int32&&>::Value));
 | 
			
		||||
	always_check((TIsSame<decltype(DeclVal<const volatile TTuple<const volatile int32&&, char>&&>().GetValue<0>()), const volatile int32&&>::Value));
 | 
			
		||||
 | 
			
		||||
	always_check((TIsSame<TTupleElementType<0,                TTuple<double, float&, char&&>>::Type,                double>::Value));
 | 
			
		||||
	always_check((TIsSame<TTupleElementType<1,                TTuple<double, float&, char&&>>::Type,                float&>::Value));
 | 
			
		||||
@@ -660,11 +661,11 @@ void TestTuple()
 | 
			
		||||
	always_check((TTupleElementIndex<float&, const volatile TTuple<double, float&, char&&>>::Value == 1));
 | 
			
		||||
	always_check((TTupleElementIndex<char&&, const volatile TTuple<double, float&, char&&>>::Value == 2));
 | 
			
		||||
 | 
			
		||||
	always_check((TTupleElementIndex<int, TTuple<double, float&, char&&>>::Value == INDEX_NONE));
 | 
			
		||||
	always_check((TTupleElementIndex<int32, TTuple<double, float&, char&&>>::Value == INDEX_NONE));
 | 
			
		||||
 | 
			
		||||
//	always_check((TIsSame<TTupleElementType<0, int>::Type, double>::Value));
 | 
			
		||||
//	always_check((TIsSame<TTupleElementType<0, int32>::Type, double>::Value));
 | 
			
		||||
 | 
			
		||||
//	always_check((TTupleElementIndex<int, int>::Value == 0));
 | 
			
		||||
//	always_check((TTupleElementIndex<int32, int32>::Value == 0));
 | 
			
		||||
 | 
			
		||||
//	always_check((TIsSame<TTupleElementType<4, TTuple<double, float&, char&&>>::Type, double>::Value));
 | 
			
		||||
 | 
			
		||||
@@ -910,6 +911,254 @@ void TestTuple()
 | 
			
		||||
 | 
			
		||||
NAMESPACE_UNNAMED_BEGIN
 | 
			
		||||
 | 
			
		||||
struct FFunctionDebug
 | 
			
		||||
{
 | 
			
		||||
	int32 Index = 0;
 | 
			
		||||
	int32 Output[12];
 | 
			
		||||
	void Print(int32 In) { Output[Index++] = In; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FFunctionDebug FunctionDebug;
 | 
			
		||||
 | 
			
		||||
struct FPrintAdd
 | 
			
		||||
{
 | 
			
		||||
	FPrintAdd(int32 InNum) : Num(InNum) { }
 | 
			
		||||
	void F(int32 I) const { FunctionDebug.Print(Num + I); }
 | 
			
		||||
	int32 Num;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void PrintNum(int32 I)
 | 
			
		||||
{
 | 
			
		||||
	FunctionDebug.Print(I);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct FPrintNum
 | 
			
		||||
{
 | 
			
		||||
	void operator()(int32 I) const
 | 
			
		||||
	{
 | 
			
		||||
		FunctionDebug.Print(I);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
NAMESPACE_UNNAMED_END
 | 
			
		||||
 | 
			
		||||
void TestFunction()
 | 
			
		||||
{
 | 
			
		||||
	{
 | 
			
		||||
//		TFunctionRef<void()> TempA;
 | 
			
		||||
		TFunction<void()> TempB;
 | 
			
		||||
		TUniqueFunction<void()> TempC;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		struct FFunctor
 | 
			
		||||
		{
 | 
			
		||||
			int32 operator()() &       { return 0; }
 | 
			
		||||
			int32 operator()() &&      { return 1; }
 | 
			
		||||
			int32 operator()() const&  { return 2; }
 | 
			
		||||
			int32 operator()() const&& { return 3; }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		FFunctor Functor;
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<int32()        > TempA = Functor;
 | 
			
		||||
		TFunctionRef<int32() &      > TempB = Functor;
 | 
			
		||||
		TFunctionRef<int32() &&     > TempC = Functor;
 | 
			
		||||
		TFunctionRef<int32() const  > TempD = Functor;
 | 
			
		||||
		TFunctionRef<int32() const& > TempE = Functor;
 | 
			
		||||
		TFunctionRef<int32() const&&> TempF = Functor;
 | 
			
		||||
 | 
			
		||||
		always_check(         TempA()  == 0);
 | 
			
		||||
		always_check(         TempB()  == 0);
 | 
			
		||||
		always_check(MoveTemp(TempC)() == 1);
 | 
			
		||||
		always_check(         TempD()  == 2);
 | 
			
		||||
		always_check(         TempE()  == 2);
 | 
			
		||||
		always_check(MoveTemp(TempF)() == 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		int32 Offset = 0xFA00;
 | 
			
		||||
		auto FuncA = [&Offset](int32 In) { return In + Offset; };
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<int32(int32)> TempA = FuncA;
 | 
			
		||||
		Offset = 0xFB00;
 | 
			
		||||
		always_check(TempA(0xAA) == 0xFBAA);
 | 
			
		||||
 | 
			
		||||
		TFunction<int32(int32)> TempB = FuncA;
 | 
			
		||||
		Offset = 0xFC00;
 | 
			
		||||
		always_check(TempB(0xAB) == 0xFCAB);
 | 
			
		||||
 | 
			
		||||
		TUniqueFunction<int32(int32)> TempC = FuncA;
 | 
			
		||||
		Offset = 0xFD00;
 | 
			
		||||
		always_check(TempC(0xAC) == 0xFDAC);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		struct FFunctor
 | 
			
		||||
		{
 | 
			
		||||
			int32 A;
 | 
			
		||||
			FFunctor(int32 InA) : A(InA) { }
 | 
			
		||||
			int32 operator()() const { return A; }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		TFunction<void()> TempA = FFunctor(0xAA);
 | 
			
		||||
		TFunction<void()> TempB(InPlaceType<FFunctor>, 0xBB);
 | 
			
		||||
 | 
			
		||||
		TempA();
 | 
			
		||||
		TempB();
 | 
			
		||||
 | 
			
		||||
		TFunction<int32()> TempC = FFunctor(0xAA);
 | 
			
		||||
		TFunction<int32()> TempD(InPlaceType<FFunctor>, 0xBB);
 | 
			
		||||
 | 
			
		||||
		always_check(TempC() == 0xAA);
 | 
			
		||||
		always_check(TempD() == 0xBB);
 | 
			
		||||
 | 
			
		||||
		TempA = nullptr;
 | 
			
		||||
		TempB = nullptr;
 | 
			
		||||
 | 
			
		||||
		always_check(!TempA.IsValid());
 | 
			
		||||
		always_check(!TempB.IsValid());
 | 
			
		||||
 | 
			
		||||
		TempA = FFunctor(0xCC);
 | 
			
		||||
		TempB.Emplace<FFunctor>(0xDD);
 | 
			
		||||
 | 
			
		||||
		always_check(TempA.IsValid());
 | 
			
		||||
		always_check(TempB.IsValid());
 | 
			
		||||
 | 
			
		||||
		TempA();
 | 
			
		||||
		TempB();
 | 
			
		||||
 | 
			
		||||
		TempC.Reset();
 | 
			
		||||
		TempD.Reset();
 | 
			
		||||
 | 
			
		||||
		always_check(!TempC.IsValid());
 | 
			
		||||
		always_check(!TempD.IsValid());
 | 
			
		||||
 | 
			
		||||
		TempC = FFunctor(0xEE);
 | 
			
		||||
		TempD.Emplace<FFunctor>(0xFF);
 | 
			
		||||
 | 
			
		||||
		always_check(TempC.IsValid());
 | 
			
		||||
		always_check(TempD.IsValid());
 | 
			
		||||
 | 
			
		||||
		always_check(TempC() == 0xEE);
 | 
			
		||||
		always_check(TempD() == 0xFF);
 | 
			
		||||
 | 
			
		||||
		always_check(TempC.TargetType() == Typeid(FFunctor));
 | 
			
		||||
		always_check(TempD.TargetType() == Typeid(FFunctor));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		TFunctionRef<void()>       RefA = [] { };
 | 
			
		||||
		TFunction<void()>       ObjectA = [] { };
 | 
			
		||||
		TUniqueFunction<void()> UniqueA = [] { };
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<void()>       RefB = RefA;
 | 
			
		||||
//		TFunction<void()>       ObjectB = RefA;
 | 
			
		||||
//		TUniqueFunction<void()> UniqueB = RefA;
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<void()>       RefC = ObjectA;
 | 
			
		||||
		TFunction<void()>       ObjectC = ObjectA;
 | 
			
		||||
		TUniqueFunction<void()> UniqueC = ObjectA;
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<void()>       RefD = UniqueA;
 | 
			
		||||
//		TFunction<void()>       ObjectD = UniqueA;
 | 
			
		||||
//		TUniqueFunction<void()> UniqueD = UniqueA;
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<void()>       RefE = MoveTemp(RefA);
 | 
			
		||||
//		TFunction<void()>       ObjectE = MoveTemp(RefA);
 | 
			
		||||
//		TUniqueFunction<void()> UniqueE = MoveTemp(RefA);
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<void()>       RefF = MoveTemp(ObjectA);
 | 
			
		||||
		TFunction<void()>       ObjectF = MoveTemp(ObjectA);
 | 
			
		||||
		TUniqueFunction<void()> UniqueF = MoveTemp(ObjectA);
 | 
			
		||||
 | 
			
		||||
		TFunctionRef<void()>       RefG = MoveTemp(UniqueA);
 | 
			
		||||
//		TFunction<void()>       ObjectG = MoveTemp(UniqueA);
 | 
			
		||||
		TUniqueFunction<void()> UniqueG = MoveTemp(UniqueA);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	{
 | 
			
		||||
		TFunctionRef<void()>       RefA = [] { };
 | 
			
		||||
		TFunction<void()>       ObjectA = [] { };
 | 
			
		||||
		TUniqueFunction<void()> UniqueA = [] { };
 | 
			
		||||
 | 
			
		||||
//		TFunctionRef<void()>       RefB;    RefB = RefA;
 | 
			
		||||
//		TFunction<void()>       ObjectB; ObjectB = RefA;
 | 
			
		||||
//		TUniqueFunction<void()> UniqueB; UniqueB = RefA;
 | 
			
		||||
 | 
			
		||||
//		TFunctionRef<void()>       RefC;    RefC = ObjectA;
 | 
			
		||||
		TFunction<void()>       ObjectC; ObjectC = ObjectA;
 | 
			
		||||
		TUniqueFunction<void()> UniqueC; UniqueC = ObjectA;
 | 
			
		||||
 | 
			
		||||
//		TFunctionRef<void()>       RefD;    RefD = UniqueA;
 | 
			
		||||
//		TFunction<void()>       ObjectD; ObjectD = UniqueA;
 | 
			
		||||
//		TUniqueFunction<void()> UniqueD; UniqueD = UniqueA;
 | 
			
		||||
		
 | 
			
		||||
//		TFunctionRef<void()>       RefE;    RefE = MoveTemp(RefA);
 | 
			
		||||
//		TFunction<void()>       ObjectE; ObjectE = MoveTemp(RefA);
 | 
			
		||||
//		TUniqueFunction<void()> UniqueE; UniqueE = MoveTemp(RefA);
 | 
			
		||||
 | 
			
		||||
//		TFunctionRef<void()>       RefF;    RefF = MoveTemp(ObjectA);
 | 
			
		||||
		TFunction<void()>       ObjectF; ObjectF = MoveTemp(ObjectA);
 | 
			
		||||
		TUniqueFunction<void()> UniqueF; UniqueF = MoveTemp(ObjectA);
 | 
			
		||||
 | 
			
		||||
//		TFunctionRef<void()>       RefG;    RefG = MoveTemp(UniqueA);
 | 
			
		||||
//		TFunction<void()>       ObjectG; ObjectG = MoveTemp(UniqueA);
 | 
			
		||||
		TUniqueFunction<void()> UniqueG; UniqueG = MoveTemp(UniqueA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		TFunction<void(int32)> Display = PrintNum;
 | 
			
		||||
		Display(-9);
 | 
			
		||||
 | 
			
		||||
		TFunction<void()> Display42 = [] { PrintNum(42); };
 | 
			
		||||
		Display42();
 | 
			
		||||
 | 
			
		||||
		TFunction<void()> Display31337 = [] { PrintNum(31337); };
 | 
			
		||||
		Display31337();
 | 
			
		||||
 | 
			
		||||
		TFunction<void(const FPrintAdd&, int32)> AddDisplay = &FPrintAdd::F;
 | 
			
		||||
		const FPrintAdd Foo(314159);
 | 
			
		||||
		AddDisplay(Foo, 1);
 | 
			
		||||
		AddDisplay(314159, 1);
 | 
			
		||||
 | 
			
		||||
		TFunction<int32(FPrintAdd const&)> Num = &FPrintAdd::Num;
 | 
			
		||||
		FunctionDebug.Print(Num(Foo));
 | 
			
		||||
 | 
			
		||||
		TFunction<void(int32)> AddDisplay2 = [Foo](int32 A) { Foo.F(A); };
 | 
			
		||||
		AddDisplay2(2);
 | 
			
		||||
 | 
			
		||||
		TFunction<void(int32)> AddDisplay3 = [Ptr = &Foo](int32 A) { Ptr->F(A); };
 | 
			
		||||
		AddDisplay3(3);
 | 
			
		||||
 | 
			
		||||
		TFunction<void(int32)> DisplayObject = FPrintNum();
 | 
			
		||||
		DisplayObject(18);
 | 
			
		||||
 | 
			
		||||
		auto Factorial = [](int32 N) {
 | 
			
		||||
			TFunction<int32(int32)> Fac = [&](int32 N) { return (N < 2) ? 1 : N * Fac(N - 1); };
 | 
			
		||||
			return Fac(N);
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		for (int32 I = 5; I < 8; ++I) FunctionDebug.Print(Factorial(I));
 | 
			
		||||
 | 
			
		||||
		always_check(FunctionDebug.Index == 12);
 | 
			
		||||
		always_check(FunctionDebug.Output[0] == -9);
 | 
			
		||||
		always_check(FunctionDebug.Output[1] == 42);
 | 
			
		||||
		always_check(FunctionDebug.Output[2] == 31337);
 | 
			
		||||
		always_check(FunctionDebug.Output[3] == 314160);
 | 
			
		||||
		always_check(FunctionDebug.Output[4] == 314160);
 | 
			
		||||
		always_check(FunctionDebug.Output[5] == 314159);
 | 
			
		||||
		always_check(FunctionDebug.Output[6] == 314161);
 | 
			
		||||
		always_check(FunctionDebug.Output[7] == 314162);
 | 
			
		||||
		always_check(FunctionDebug.Output[8] == 18);
 | 
			
		||||
		always_check(FunctionDebug.Output[9] == 120);
 | 
			
		||||
		always_check(FunctionDebug.Output[10] == 720);
 | 
			
		||||
		always_check(FunctionDebug.Output[11] == 5040);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NAMESPACE_UNNAMED_BEGIN
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct TTestStructA
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										459
									
								
								Redcraft.Utility/Source/Public/Templates/Function.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										459
									
								
								Redcraft.Utility/Source/Public/Templates/Function.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,459 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "CoreTypes.h"
 | 
			
		||||
#include "Memory/Memory.h"
 | 
			
		||||
#include "Templates/Any.h"
 | 
			
		||||
#include "Templates/Tuple.h"
 | 
			
		||||
#include "Templates/Invoke.h"
 | 
			
		||||
#include "Templates/Container.h"
 | 
			
		||||
#include "TypeTraits/TypeTraits.h"
 | 
			
		||||
#include "Miscellaneous/TypeInfo.h"
 | 
			
		||||
#include "Miscellaneous/AssertionMacros.h"
 | 
			
		||||
 | 
			
		||||
NAMESPACE_REDCRAFT_BEGIN
 | 
			
		||||
NAMESPACE_MODULE_BEGIN(Redcraft)
 | 
			
		||||
NAMESPACE_MODULE_BEGIN(Utility)
 | 
			
		||||
 | 
			
		||||
NAMESPACE_PRIVATE_BEGIN
 | 
			
		||||
 | 
			
		||||
enum class EFunctionType
 | 
			
		||||
{
 | 
			
		||||
	Reference,
 | 
			
		||||
	Object,
 | 
			
		||||
	Unique,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class EFunctionSpecifiers
 | 
			
		||||
{
 | 
			
		||||
	None,
 | 
			
		||||
	LValue,
 | 
			
		||||
	RValue,
 | 
			
		||||
	Const,
 | 
			
		||||
	ConstLValue,
 | 
			
		||||
	ConstRValue,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename F, size_t InlineSize, size_t InlineAlignment, EFunctionSpecifiers Specifiers, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionImpl;
 | 
			
		||||
 | 
			
		||||
template <typename T>                                                             struct TIsTFunctionImpl                               : FFalse { };
 | 
			
		||||
template <typename F, size_t I, size_t J, EFunctionSpecifiers S, EFunctionType E> struct TIsTFunctionImpl<TFunctionImpl<F, I, J, S, E>> : FTrue  { };
 | 
			
		||||
 | 
			
		||||
template <typename T>                                            struct TIsTFunctionRef                                                      : FFalse { };
 | 
			
		||||
template <typename F, size_t I, size_t J, EFunctionSpecifiers S> struct TIsTFunctionRef<TFunctionImpl<F, I, J, S, EFunctionType::Reference>> : FTrue  { };
 | 
			
		||||
 | 
			
		||||
template <typename T>                                            struct TIsTFunction                                                   : FFalse { };
 | 
			
		||||
template <typename F, size_t I, size_t J, EFunctionSpecifiers S> struct TIsTFunction<TFunctionImpl<F, I, J, S, EFunctionType::Object>> : FTrue  { };
 | 
			
		||||
 | 
			
		||||
template <typename T>                                            struct TIsTUniqueFunction                                                   : FFalse { };
 | 
			
		||||
template <typename F, size_t I, size_t J, EFunctionSpecifiers S> struct TIsTUniqueFunction<TFunctionImpl<F, I, J, S, EFunctionType::Unique>> : FTrue  { };
 | 
			
		||||
 | 
			
		||||
struct FFunctionIsBoundImpl
 | 
			
		||||
{
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	static constexpr bool F(const T& Func)
 | 
			
		||||
	{
 | 
			
		||||
		if constexpr (TIsPointer<T>::Value || TIsMemberPointer<T>::Value || TIsTFunctionImpl<T>::Value)
 | 
			
		||||
		{
 | 
			
		||||
			return !!Func;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <EFunctionSpecifiers Specifiers, typename R, typename F, typename... Types>
 | 
			
		||||
struct TIsInvocableResultWithSpecifiers : FFalse { };
 | 
			
		||||
 | 
			
		||||
template <typename R, typename F, typename... Types>
 | 
			
		||||
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::None, R, F, Types...>
 | 
			
		||||
	: TBoolConstant<TIsInvocableResult<R, F, Types...>::Value && TIsInvocableResult<R, F&, Types...>::Value>
 | 
			
		||||
{ };
 | 
			
		||||
 | 
			
		||||
template <typename R, typename F, typename... Types>
 | 
			
		||||
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::LValue, R, F, Types...> : TIsInvocableResult<R, F&, Types...> { };
 | 
			
		||||
 | 
			
		||||
template <typename R, typename F, typename... Types>
 | 
			
		||||
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::RValue, R, F, Types...> : TIsInvocableResult<R, F, Types...> { };
 | 
			
		||||
 | 
			
		||||
template <typename R, typename F, typename... Types>
 | 
			
		||||
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::Const, R, F, Types...>
 | 
			
		||||
	: TBoolConstant<TIsInvocableResult<R, const F, Types...>::Value && TIsInvocableResult<R, const F&, Types...>::Value>
 | 
			
		||||
{ };
 | 
			
		||||
 | 
			
		||||
template <typename R, typename F, typename... Types>
 | 
			
		||||
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::ConstLValue, R, F, Types...> : TIsInvocableResult<R, const F&, Types...> { };
 | 
			
		||||
 | 
			
		||||
template <typename R, typename F, typename... Types>
 | 
			
		||||
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::ConstRValue, R, F, Types...> : TIsInvocableResult<R, const F, Types...> { };
 | 
			
		||||
 | 
			
		||||
template <EFunctionSpecifiers Specifiers, typename T, typename F>
 | 
			
		||||
struct TFunctionCallImpl;
 | 
			
		||||
 | 
			
		||||
template <typename T, typename R, typename... Types>
 | 
			
		||||
struct TFunctionCallImpl<EFunctionSpecifiers::None, T, R(Types...)>
 | 
			
		||||
{
 | 
			
		||||
	static inline R F(void* Func, Types&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		return InvokeResult<R>(*reinterpret_cast<T*>(Func), Forward<Types>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename R, typename... Types>
 | 
			
		||||
struct TFunctionCallImpl<EFunctionSpecifiers::LValue, T, R(Types...)>
 | 
			
		||||
{
 | 
			
		||||
	static inline R F(void* Func, Types&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		return InvokeResult<R>(*reinterpret_cast<T*>(Func), Forward<Types>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename R, typename... Types>
 | 
			
		||||
struct TFunctionCallImpl<EFunctionSpecifiers::RValue, T, R(Types...)>
 | 
			
		||||
{
 | 
			
		||||
	static inline R F(void* Func, Types&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		return InvokeResult<R>(MoveTemp(*reinterpret_cast<T*>(Func)), Forward<Types>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename R, typename... Types>
 | 
			
		||||
struct TFunctionCallImpl<EFunctionSpecifiers::Const, T, R(Types...)>
 | 
			
		||||
{
 | 
			
		||||
	static inline R F(void* Func, Types&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		return InvokeResult<R>(AsConst(*reinterpret_cast<T*>(Func)), Forward<Types>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename R, typename... Types>
 | 
			
		||||
struct TFunctionCallImpl<EFunctionSpecifiers::ConstLValue, T, R(Types...)>
 | 
			
		||||
{
 | 
			
		||||
	static inline R F(void* Func, Types&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		return InvokeResult<R>(AsConst(*reinterpret_cast<T*>(Func)), Forward<Types>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename R, typename... Types>
 | 
			
		||||
struct TFunctionCallImpl<EFunctionSpecifiers::ConstRValue, T, R(Types...)>
 | 
			
		||||
{
 | 
			
		||||
	static inline R F(void* Func, Types&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		return InvokeResult<R>(MoveTemp(AsConst(*reinterpret_cast<T*>(Func))), Forward<Types>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionSpecifiers Specifiers, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, FunctionType>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	using ResultType = R;
 | 
			
		||||
	using ArgumentType = TTuple<Types...>;
 | 
			
		||||
 | 
			
		||||
	constexpr TFunctionImpl(nullptr_t = nullptr) requires (FunctionType != EFunctionType::Reference) : Call(nullptr) { }
 | 
			
		||||
 | 
			
		||||
	TFunctionImpl(const TFunctionImpl& InValue) requires (FunctionType != EFunctionType::Unique)
 | 
			
		||||
		: Call(InValue.Call), Storage(InValue.Storage)
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
	TFunctionImpl(TFunctionImpl&& InValue)
 | 
			
		||||
		: Call(InValue.Call), Storage(MoveTemp(InValue.Storage))
 | 
			
		||||
	{ if constexpr (FunctionType != EFunctionType::Reference) InValue.Reset(); }
 | 
			
		||||
	
 | 
			
		||||
	template <typename T> requires (!TIsTFunctionImpl<typename TDecay<T>::Type>::Value) && (!TIsTInPlaceType<typename TDecay<T>::Type>::Value)
 | 
			
		||||
		&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value
 | 
			
		||||
		&& (FunctionType == EFunctionType::Reference || TIsConstructible<typename TDecay<T>::Type, T&&>::Value)
 | 
			
		||||
		&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
 | 
			
		||||
			|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value)
 | 
			
		||||
			|| FunctionType == EFunctionType::Reference)
 | 
			
		||||
	FORCEINLINE TFunctionImpl(T&& InValue)
 | 
			
		||||
	{
 | 
			
		||||
		using DecayedFunctorType = typename TDecay<T>::Type;
 | 
			
		||||
 | 
			
		||||
		if constexpr (FunctionType == EFunctionType::Reference)
 | 
			
		||||
		{
 | 
			
		||||
			checkf(FFunctionIsBoundImpl::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!FFunctionIsBoundImpl::F(InValue)) Call = nullptr;
 | 
			
		||||
		else EmplaceImpl<DecayedFunctorType>(Forward<T>(InValue));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T, typename... ArgTypes> requires (FunctionType != EFunctionType::Reference)
 | 
			
		||||
		&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value && TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value
 | 
			
		||||
		&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
 | 
			
		||||
			|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
 | 
			
		||||
	FORCEINLINE TFunctionImpl(TInPlaceType<T>, ArgTypes&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		using DecayedFunctorType = typename TDecay<T>::Type;
 | 
			
		||||
		EmplaceImpl<DecayedFunctorType>(Forward<ArgTypes>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <size_t OtherInlineSize, size_t OtherInlineAlignment, EFunctionType OtherFunctionType>
 | 
			
		||||
		requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference)
 | 
			
		||||
	FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>& InValue)
 | 
			
		||||
	{
 | 
			
		||||
		checkf(FFunctionIsBoundImpl::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
 | 
			
		||||
		EmplaceImpl<TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>>(InValue);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>& InValue) requires (FunctionType == EFunctionType::Unique)
 | 
			
		||||
		: Call((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Call), Storage((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Storage)
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE TFunctionImpl(TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>&& InValue) requires (FunctionType == EFunctionType::Unique)
 | 
			
		||||
		: Call((*reinterpret_cast<TFunctionImpl*>(&InValue)).Call), Storage(MoveTemp((*reinterpret_cast<TFunctionImpl*>(&InValue)).Storage))
 | 
			
		||||
	{ InValue.Reset(); }
 | 
			
		||||
 | 
			
		||||
	~TFunctionImpl() = default;
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE TFunctionImpl& operator=(const TFunctionImpl& InValue) requires (FunctionType == EFunctionType::Object)
 | 
			
		||||
	{
 | 
			
		||||
		AssignImpl(InValue);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE TFunctionImpl& operator=(TFunctionImpl&& InValue) requires (FunctionType != EFunctionType::Reference)
 | 
			
		||||
	{
 | 
			
		||||
		if (&InValue == this) return *this;
 | 
			
		||||
		AssignImpl(MoveTemp(InValue));
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE TFunctionImpl& operator=(const TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>& InValue) requires (FunctionType == EFunctionType::Unique)
 | 
			
		||||
	{
 | 
			
		||||
		AssignImpl(*reinterpret_cast<const TFunctionImpl*>(&InValue));
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE TFunctionImpl& operator=(TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>&& InValue) requires (FunctionType == EFunctionType::Unique)
 | 
			
		||||
	{
 | 
			
		||||
		AssignImpl(MoveTemp(*reinterpret_cast<TFunctionImpl*>(&InValue)));
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constexpr TFunctionImpl& operator=(nullptr_t) requires (FunctionType != EFunctionType::Reference) { Reset(); return *this; }
 | 
			
		||||
 | 
			
		||||
	template <typename T> requires (FunctionType != EFunctionType::Reference) && (!TIsTFunctionImpl<typename TDecay<T>::Type>::Value)
 | 
			
		||||
		&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value
 | 
			
		||||
		&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value
 | 
			
		||||
		&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
 | 
			
		||||
			|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
 | 
			
		||||
	FORCEINLINE TFunctionImpl& operator=(T&& InValue)
 | 
			
		||||
	{
 | 
			
		||||
		using DecayedFunctorType = typename TDecay<T>::Type;
 | 
			
		||||
 | 
			
		||||
		if (!FFunctionIsBoundImpl::F(InValue)) Reset();
 | 
			
		||||
		else EmplaceImpl<DecayedFunctorType>(Forward<T>(InValue));
 | 
			
		||||
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T, typename... ArgTypes> requires (FunctionType != EFunctionType::Reference)
 | 
			
		||||
		&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value
 | 
			
		||||
		&& TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value
 | 
			
		||||
		&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
 | 
			
		||||
			|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
 | 
			
		||||
	FORCEINLINE typename TDecay<T>::Type& Emplace(ArgTypes&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		using DecayedFunctorType = typename TDecay<T>::Type;
 | 
			
		||||
		EmplaceImpl<DecayedFunctorType>(Forward<ArgTypes>(Args)...);
 | 
			
		||||
		return *reinterpret_cast<typename TDecay<T>::Type*>(Target());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE ResultType operator()(Types... Args)         requires (Specifiers == EFunctionSpecifiers::None       ) { return CallImpl(Forward<Types>(Args)...); }
 | 
			
		||||
	FORCEINLINE ResultType operator()(Types... Args) &       requires (Specifiers == EFunctionSpecifiers::LValue     ) { return CallImpl(Forward<Types>(Args)...); }
 | 
			
		||||
	FORCEINLINE ResultType operator()(Types... Args) &&      requires (Specifiers == EFunctionSpecifiers::RValue     ) { return CallImpl(Forward<Types>(Args)...); }
 | 
			
		||||
	FORCEINLINE ResultType operator()(Types... Args) const   requires (Specifiers == EFunctionSpecifiers::Const      ) { return CallImpl(Forward<Types>(Args)...); }
 | 
			
		||||
	FORCEINLINE ResultType operator()(Types... Args) const&  requires (Specifiers == EFunctionSpecifiers::ConstLValue) { return CallImpl(Forward<Types>(Args)...); }
 | 
			
		||||
	FORCEINLINE ResultType operator()(Types... Args) const&& requires (Specifiers == EFunctionSpecifiers::ConstRValue) { return CallImpl(Forward<Types>(Args)...); }
 | 
			
		||||
 | 
			
		||||
	constexpr bool           IsValid() const { return Call != nullptr; }
 | 
			
		||||
	constexpr explicit operator bool() const { return Call != nullptr; }
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE const FTypeInfo& TargetType() const requires (FunctionType != EFunctionType::Reference) { return IsValid() ? Storage.GetTypeInfo() : Typeid(void); };
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE       void* Target()       { if constexpr (FunctionType != EFunctionType::Reference) return Storage.GetData(); else return Storage; }
 | 
			
		||||
	FORCEINLINE const void* Target() const { if constexpr (FunctionType != EFunctionType::Reference) return Storage.GetData(); else return Storage; }
 | 
			
		||||
 | 
			
		||||
	constexpr void Reset() requires (FunctionType != EFunctionType::Reference) { Call = nullptr; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	using CallFunc = ResultType(*)(void*, Types&&...);
 | 
			
		||||
	using StorageType = typename TConditional<FunctionType == EFunctionType::Reference, void*, TAny<InlineSize, InlineAlignment>>::Type;
 | 
			
		||||
 | 
			
		||||
	CallFunc Call;
 | 
			
		||||
	StorageType Storage;
 | 
			
		||||
 | 
			
		||||
	template <typename SelectedType, typename... ArgTypes>
 | 
			
		||||
	FORCEINLINE void EmplaceImpl(ArgTypes&&... Args)
 | 
			
		||||
	{
 | 
			
		||||
		if constexpr (FunctionType == EFunctionType::Reference) Storage = ((void*)&Args, ...);
 | 
			
		||||
		else Storage.template Emplace<SelectedType>(Forward<ArgTypes>(Args)...);
 | 
			
		||||
		Call = &TFunctionCallImpl<Specifiers, SelectedType, ResultType(Types...)>::F;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE ResultType CallImpl(Types&&... Args) const
 | 
			
		||||
	{
 | 
			
		||||
		checkf(IsValid(), TEXT("Attempting to call an unbound TFunction!"));
 | 
			
		||||
		return Call(const_cast<TFunctionImpl&>(*this).Target(), Forward<Types>(Args)...);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE void AssignImpl(const TFunctionImpl& InValue)
 | 
			
		||||
	{
 | 
			
		||||
		if (InValue.IsValid())
 | 
			
		||||
		{
 | 
			
		||||
			Call = InValue.Call;
 | 
			
		||||
			Storage = InValue.Storage;
 | 
			
		||||
		}
 | 
			
		||||
		else Reset();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FORCEINLINE void AssignImpl(TFunctionImpl&& InValue)
 | 
			
		||||
	{
 | 
			
		||||
		if (InValue.IsValid())
 | 
			
		||||
		{
 | 
			
		||||
			Call = InValue.Call;
 | 
			
		||||
			Storage = MoveTemp(InValue.Storage);
 | 
			
		||||
			InValue.Reset();
 | 
			
		||||
		}
 | 
			
		||||
		else Reset();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename F, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionSelect;
 | 
			
		||||
 | 
			
		||||
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionSelect<R(Types...)        , InlineSize, InlineAlignment, FunctionType>
 | 
			
		||||
{
 | 
			
		||||
	using Type = NAMESPACE_PRIVATE::TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::None, FunctionType>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionSelect<R(Types...) &      , InlineSize, InlineAlignment, FunctionType>
 | 
			
		||||
{
 | 
			
		||||
	using Type = NAMESPACE_PRIVATE::TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::LValue, FunctionType>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionSelect<R(Types...) &&     , InlineSize, InlineAlignment, FunctionType>
 | 
			
		||||
{
 | 
			
		||||
	using Type = NAMESPACE_PRIVATE::TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::RValue, FunctionType>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionSelect<R(Types...) const  , InlineSize, InlineAlignment, FunctionType>
 | 
			
		||||
{
 | 
			
		||||
	using Type = NAMESPACE_PRIVATE::TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::Const, FunctionType>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionSelect<R(Types...) const& , InlineSize, InlineAlignment, FunctionType>
 | 
			
		||||
{
 | 
			
		||||
	using Type = NAMESPACE_PRIVATE::TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::ConstLValue, FunctionType>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
 | 
			
		||||
struct TFunctionSelect<R(Types...) const&&, InlineSize, InlineAlignment, FunctionType>
 | 
			
		||||
{
 | 
			
		||||
	using Type = NAMESPACE_PRIVATE::TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::ConstRValue, FunctionType>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
NAMESPACE_PRIVATE_END
 | 
			
		||||
 | 
			
		||||
inline constexpr size_t FUNCTION_DEFAULT_INLINE_SIZE      = 32;
 | 
			
		||||
inline constexpr size_t FUNCTION_DEFAULT_INLINE_ALIGNMENT = 16;
 | 
			
		||||
 | 
			
		||||
template <typename F>
 | 
			
		||||
using TFunctionRef = typename NAMESPACE_PRIVATE::TFunctionSelect<F, INDEX_NONE, INDEX_NONE, NAMESPACE_PRIVATE::EFunctionType::Reference>::Type;
 | 
			
		||||
 | 
			
		||||
template <typename F, size_t InlineSize = FUNCTION_DEFAULT_INLINE_SIZE, size_t InlineAlignment = FUNCTION_DEFAULT_INLINE_ALIGNMENT>
 | 
			
		||||
using TFunction = typename NAMESPACE_PRIVATE::TFunctionSelect<F, InlineSize, InlineAlignment, NAMESPACE_PRIVATE::EFunctionType::Object>::Type;
 | 
			
		||||
 | 
			
		||||
template <typename F, size_t InlineSize = FUNCTION_DEFAULT_INLINE_SIZE, size_t InlineAlignment = FUNCTION_DEFAULT_INLINE_ALIGNMENT>
 | 
			
		||||
using TUniqueFunction = typename NAMESPACE_PRIVATE::TFunctionSelect<F, InlineSize, InlineAlignment, NAMESPACE_PRIVATE::EFunctionType::Unique>::Type;
 | 
			
		||||
 | 
			
		||||
template <typename T> struct TIsTFunctionRef    : NAMESPACE_PRIVATE::TIsTFunctionRef<T>    { };
 | 
			
		||||
template <typename T> struct TIsTFunction       : NAMESPACE_PRIVATE::TIsTFunction<T>       { };
 | 
			
		||||
template <typename T> struct TIsTUniqueFunction : NAMESPACE_PRIVATE::TIsTUniqueFunction<T> { };
 | 
			
		||||
 | 
			
		||||
template <typename F>
 | 
			
		||||
constexpr bool operator==(const TFunctionRef<F>& LHS, nullptr_t)
 | 
			
		||||
{
 | 
			
		||||
	return !LHS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename F>
 | 
			
		||||
constexpr bool operator==(const TFunction<F>& LHS, nullptr_t)
 | 
			
		||||
{
 | 
			
		||||
	return !LHS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename F>
 | 
			
		||||
constexpr bool operator==(const TUniqueFunction<F>& LHS, nullptr_t)
 | 
			
		||||
{
 | 
			
		||||
	return !LHS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename F, size_t I, size_t J>
 | 
			
		||||
constexpr void Swap(TFunction<F, I, J>& A, TFunction<F, I, J>& B)
 | 
			
		||||
{
 | 
			
		||||
	if (!A && !B) return;
 | 
			
		||||
 | 
			
		||||
	if (A && !B)
 | 
			
		||||
	{
 | 
			
		||||
		B = MoveTemp(A);
 | 
			
		||||
		A = nullptr;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (B && !A)
 | 
			
		||||
	{
 | 
			
		||||
		A = MoveTemp(B);
 | 
			
		||||
		B = nullptr;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TFunction<F, I, J> Temp = MoveTemp(A);
 | 
			
		||||
	A = MoveTemp(B);
 | 
			
		||||
	B = MoveTemp(Temp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename F, size_t I, size_t J>
 | 
			
		||||
constexpr void Swap(TUniqueFunction<F, I, J>& A, TUniqueFunction<F, I, J>& B)
 | 
			
		||||
{
 | 
			
		||||
	if (!A && !B) return;
 | 
			
		||||
 | 
			
		||||
	if (A && !B)
 | 
			
		||||
	{
 | 
			
		||||
		B = MoveTemp(A);
 | 
			
		||||
		A = nullptr;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (B && !A)
 | 
			
		||||
	{
 | 
			
		||||
		A = MoveTemp(B);
 | 
			
		||||
		B = nullptr;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TFunction<F, I, J> Temp = MoveTemp(A);
 | 
			
		||||
	A = MoveTemp(B);
 | 
			
		||||
	B = MoveTemp(Temp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(TFunctionRef<void()>)    == 16, "The byte size of TFunctionRef is unexpected");
 | 
			
		||||
static_assert(sizeof(TFunction<void()>)       == 64, "The byte size of TFunction is unexpected");
 | 
			
		||||
static_assert(sizeof(TUniqueFunction<void()>) == 64, "The byte size of TUniqueFunction is unexpected");
 | 
			
		||||
 | 
			
		||||
NAMESPACE_MODULE_END(Utility)
 | 
			
		||||
NAMESPACE_MODULE_END(Redcraft)
 | 
			
		||||
NAMESPACE_REDCRAFT_END
 | 
			
		||||
@@ -12,3 +12,4 @@
 | 
			
		||||
#include "Templates/IntegerSequence.h"
 | 
			
		||||
#include "Templates/Tuple.h"
 | 
			
		||||
#include "Templates/TypeHash.h"
 | 
			
		||||
#include "Templates/Function.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ REDCRAFTUTILITY_API void TestOptional();
 | 
			
		||||
REDCRAFTUTILITY_API void TestVariant();
 | 
			
		||||
REDCRAFTUTILITY_API void TestAny();
 | 
			
		||||
REDCRAFTUTILITY_API void TestTuple();
 | 
			
		||||
REDCRAFTUTILITY_API void TestFunction();
 | 
			
		||||
REDCRAFTUTILITY_API void TestMiscTemplates();
 | 
			
		||||
 | 
			
		||||
NAMESPACE_END(Testing)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user