Pārlūkot izejas kodu

Improve type-inference for 'apply'

Ole 9 gadi atpakaļ
vecāks
revīzija
c976b7bae5
2 mainītis faili ar 82 papildinājumiem un 22 dzēšanām
  1. 17 9
      examples/playground.cpp
  2. 65 13
      lib/luwra/stack.hpp

+ 17 - 9
examples/playground.cpp

@@ -2,22 +2,30 @@
 
 #include <string>
 #include <iostream>
+#include <functional>
 
 using namespace luwra;
 
+static int foo(int a, int b) {
+	return a + b;
+}
+
 int main() {
 	StateWrapper state;
+	push(state, 13);
+	push(state, 37);
 
-	state["t1"] = FieldVector {};
-
-	for (int i = 0; i < 50000000; i++) {
-		state["t1"]["value"] = i;
-		int j = state["t1"]["value"];
+	std::function<int(int, int)> bar(&foo);
+	std::function<int(int, int)> baz([](int a, int b) -> int {
+		return a + b;
+	});
 
-		if (j != i) {
-			return 1;
-		}
-	}
+	std::cout << apply(state, 1, &foo) << std::endl;
+	std::cout << apply(state, 1, bar) << std::endl;
+	std::cout << apply(state, 1, baz) << std::endl;
+	std::cout << apply(state, 1, [](int a, int b) -> int {
+		return a + b;
+	}) << std::endl;
 
 	return 0;
 }

+ 65 - 13
lib/luwra/stack.hpp

@@ -107,13 +107,53 @@ typename internal::Layout<S>::ReturnType direct(State* state, F&& hook, A&&... a
 	);
 }
 
+namespace internal {
+	template <typename T>
+	struct FunctionObjectHelper {
+		static_assert(sizeof(T) == -1, "Invalid template parameter to FunctionObjectHelper");
+	};
+
+	template <typename T, typename R, typename... A>
+	struct FunctionObjectHelper<R (T::*)(A...)> {
+		using Signature = R(A...);
+		using ReturnType = R;
+	};
+
+	template <typename T, typename R, typename... A>
+	struct FunctionObjectHelper<R (T::*)(A...) const>:
+		FunctionObjectHelper<R (T::*)(A...)>
+	{};
+
+	template <typename T, typename R, typename... A>
+	struct FunctionObjectHelper<R (T::*)(A...) volatile>:
+		FunctionObjectHelper<R (T::*)(A...)>
+	{};
+
+	template <typename T, typename R, typename... A>
+	struct FunctionObjectHelper<R (T::*)(A...) const volatile>:
+		FunctionObjectHelper<R (T::*)(A...)>
+	{};
+
+	template <typename T>
+	using FunctionObjectLayout =
+		Layout<typename FunctionObjectHelper<decltype(&T::operator ())>::Signature>;
+
+	template <typename T>
+	using FunctionObjectReturnType =
+		typename FunctionObjectHelper<decltype(&T::operator ())>::ReturnType;
+}
+
 /**
- * Synonym for [direct](@ref direct) with a function pointer which lets you omit all template parameters.
- * The stack layout will be inferred using the signature of the given function pointer.
+ * A version of [direct](@ref direct) which is specialized for function pointers; therefore allows
+ * you to omit the template parameters since the compiler can infer its parameter and return types.
  */
 template <typename R, typename... A> static inline
 R apply(State* state, int pos, R (* fun)(A...)) {
-	return direct<R(A...)>(state, pos, fun);
+	return internal::Layout<R(A...)>::direct(
+		state,
+		pos,
+		fun
+	);
 }
 
 /**
@@ -121,24 +161,36 @@ R apply(State* state, int pos, R (* fun)(A...)) {
  */
 template <typename R, typename... A> static inline
 R apply(State* state, R (* fun)(A...)) {
-	return apply(state, 1, fun);
+	return internal::Layout<R(A...)>::direct(
+		state,
+		1,
+		fun
+	);
 }
 
 /**
- * Synonym for [direct](@ref direct) with a function object which lets you omit all template parameters.
- * The stack layout will be inferred using the template parameter to your `std::function` object.
+ * A version of [direct](@ref direct) which tries to infer the stack layout from the given
+ * `Callable`.
  */
-template <typename R, typename... A> static inline
-R apply(State* state, int pos, const std::function<R(A...)>& fun) {
-	return internal::Layout<R(A...)>::direct(state, pos, fun);
+template <typename T> static inline
+internal::FunctionObjectReturnType<T> apply(State* state, int pos, const T& obj) {
+	return internal::FunctionObjectLayout<T>::direct(
+		state,
+		pos,
+		obj
+	);
 }
 
 /**
- * Same as `apply(state, 1, fun)`.
+ * Same as `apply(state, 1, obj)`.
  */
-template <typename R, typename... A> static inline
-R apply(State* state, const std::function<R(A...)>& fun) {
-	return apply(state, 1, fun);
+template <typename T> static inline
+internal::FunctionObjectReturnType<T> apply(State* state, const T& obj) {
+	return internal::FunctionObjectLayout<T>::direct(
+		state,
+		1,
+		obj
+	);
 }
 
 namespace internal {