diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 047d468ce..e36a9bab4 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -479,13 +479,13 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, void> { - using node_type = function_call; + template + struct ast_iterator, void> { + using node_type = function_call; template void operator()(const node_type& f, L& lambda) const { - iterate_ast(f.args, lambda); + iterate_ast(f.callArgs, lambda); } }; diff --git a/dev/function.h b/dev/function.h index bb525121a..747860aea 100644 --- a/dev/function.h +++ b/dev/function.h @@ -7,6 +7,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "functional/function_traits.h" #include "tags.h" namespace sqlite_orm { @@ -44,47 +45,30 @@ namespace sqlite_orm { std::enable_if_t>::value>>> = true; - template - struct member_function_arguments; - - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...) const; - using tuple_type = std::tuple...>; - using return_type = R; - }; - - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...); - using tuple_type = std::tuple...>; - using return_type = R; - }; - template struct callable_arguments_impl; template struct callable_arguments_impl>> { - using args_tuple = typename member_function_arguments>::tuple_type; - using return_type = typename member_function_arguments>::return_type; + using args_tuple = function_arguments, std::tuple, std::decay_t>; + using return_type = function_return_type_t>; }; template struct callable_arguments_impl>> { - using args_tuple = typename member_function_arguments>::tuple_type; - using return_type = typename member_function_arguments>::return_type; + using args_tuple = function_arguments, std::tuple, std::decay_t>; + using return_type = function_return_type_t>; }; template struct callable_arguments : callable_arguments_impl {}; - template + template struct function_call { using udf_type = UDF; - using args_tuple = std::tuple; + using args_tuple = std::tuple; - args_tuple args; + args_tuple callArgs; }; template @@ -95,8 +79,8 @@ namespace sqlite_orm { struct unpacked_arg { using type = T; }; - template - struct unpacked_arg> { + template + struct unpacked_arg> { using type = typename callable_arguments::return_type; }; template @@ -185,9 +169,9 @@ namespace sqlite_orm { */ template struct function : polyfill::type_identity { - template - function_call operator()(Args... args) const { - using args_tuple = std::tuple; + template + function_call operator()(CallArgs... callArgs) const { + using args_tuple = std::tuple; using function_args_tuple = typename callable_arguments::args_tuple; constexpr size_t argsCount = std::tuple_size::value; constexpr size_t functionArgsCount = std::tuple_size::value; @@ -197,7 +181,7 @@ namespace sqlite_orm { polyfill::index_constant{})) || std::is_same>::value, "The number of arguments does not match"); - return {{std::forward(args)...}}; + return {{std::forward(callArgs)...}}; } }; } diff --git a/dev/functional/function_traits.h b/dev/functional/function_traits.h new file mode 100644 index 000000000..5668001b3 --- /dev/null +++ b/dev/functional/function_traits.h @@ -0,0 +1,63 @@ +#pragma once +#include "cxx_type_traits_polyfill.h" +#include "mpl.h" + +namespace sqlite_orm { + namespace internal { + template + struct function_traits; + + /* + * A function's return type + */ + template + using function_return_type_t = typename function_traits::return_type; + + /* + * A function's arguments tuple + */ + template + class Tuple, + template class ProjectOp = polyfill::type_identity_t> + using function_arguments = typename function_traits::template arguments_tuple; + + /* + * Define nested typenames: + * - return_type + * - arguments_tuple + */ + template + struct function_traits { + using return_type = R; + + template class Tuple, template class ProjectOp> + using arguments_tuple = Tuple...>; + }; + + // non-exhaustive partial specializations of `function_traits` + + template + struct function_traits : function_traits {}; + +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct function_traits : function_traits {}; + + template + struct function_traits : function_traits {}; +#endif + + /* + * Pick signature of function pointer + */ + template + struct function_traits : function_traits {}; + + /* + * Pick signature of pointer-to-member function + */ + template + struct function_traits : function_traits {}; + } +} diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index dc16046a5..dc13a87b4 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -363,14 +363,14 @@ namespace sqlite_orm { struct statement_serializer, void> : statement_serializer, void> {}; - template - struct statement_serializer, void> { - using statement_type = function_call; + template + struct statement_serializer, void> { + using statement_type = function_call; template std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << F::name() << "(" << streaming_expressions_tuple(statement.args, context) << ")"; + ss << F::name() << "(" << streaming_expressions_tuple(statement.callArgs, context) << ")"; return ss.str(); } }; diff --git a/dev/storage_base.h b/dev/storage_base.h index 46c682f26..a84c37515 100644 --- a/dev/storage_base.h +++ b/dev/storage_base.h @@ -674,6 +674,7 @@ namespace sqlite_orm { auto result = polyfill::apply(udf, std::move(argsTuple)); statement_binder().result(context, result); }, + /* finalCall = */ nullptr, allocate_udf_storage()); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index da248d065..465dc02f2 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10883,6 +10883,72 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/function_traits.h" + +// #include "cxx_type_traits_polyfill.h" + +// #include "mpl.h" + +namespace sqlite_orm { + namespace internal { + template + struct function_traits; + + /* + * A function's return type + */ + template + using function_return_type_t = typename function_traits::return_type; + + /* + * A function's arguments tuple + */ + template + class Tuple, + template class ProjectOp = polyfill::type_identity_t> + using function_arguments = typename function_traits::template arguments_tuple; + + /* + * Define nested typenames: + * - return_type + * - arguments_tuple + */ + template + struct function_traits { + using return_type = R; + + template class Tuple, template class ProjectOp> + using arguments_tuple = Tuple...>; + }; + + // non-exhaustive partial specializations of `function_traits` + + template + struct function_traits : function_traits {}; + +#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED + template + struct function_traits : function_traits {}; + + template + struct function_traits : function_traits {}; +#endif + + /* + * Pick signature of function pointer + */ + template + struct function_traits : function_traits {}; + + /* + * Pick signature of pointer-to-member function + */ + template + struct function_traits : function_traits {}; + } +} + // #include "tags.h" namespace sqlite_orm { @@ -10920,47 +10986,30 @@ namespace sqlite_orm { std::enable_if_t>::value>>> = true; - template - struct member_function_arguments; - - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...) const; - using tuple_type = std::tuple...>; - using return_type = R; - }; - - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...); - using tuple_type = std::tuple...>; - using return_type = R; - }; - template struct callable_arguments_impl; template struct callable_arguments_impl>> { - using args_tuple = typename member_function_arguments>::tuple_type; - using return_type = typename member_function_arguments>::return_type; + using args_tuple = function_arguments, std::tuple, std::decay_t>; + using return_type = function_return_type_t>; }; template struct callable_arguments_impl>> { - using args_tuple = typename member_function_arguments>::tuple_type; - using return_type = typename member_function_arguments>::return_type; + using args_tuple = function_arguments, std::tuple, std::decay_t>; + using return_type = function_return_type_t>; }; template struct callable_arguments : callable_arguments_impl {}; - template + template struct function_call { using udf_type = UDF; - using args_tuple = std::tuple; + using args_tuple = std::tuple; - args_tuple args; + args_tuple callArgs; }; template @@ -10971,8 +11020,8 @@ namespace sqlite_orm { struct unpacked_arg { using type = T; }; - template - struct unpacked_arg> { + template + struct unpacked_arg> { using type = typename callable_arguments::return_type; }; template @@ -11061,9 +11110,9 @@ namespace sqlite_orm { */ template struct function : polyfill::type_identity { - template - function_call operator()(Args... args) const { - using args_tuple = std::tuple; + template + function_call operator()(CallArgs... callArgs) const { + using args_tuple = std::tuple; using function_args_tuple = typename callable_arguments::args_tuple; constexpr size_t argsCount = std::tuple_size::value; constexpr size_t functionArgsCount = std::tuple_size::value; @@ -11073,7 +11122,7 @@ namespace sqlite_orm { polyfill::index_constant{})) || std::is_same>::value, "The number of arguments does not match"); - return {{std::forward(args)...}}; + return {{std::forward(callArgs)...}}; } }; } @@ -13341,13 +13390,13 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, void> { - using node_type = function_call; + template + struct ast_iterator, void> { + using node_type = function_call; template void operator()(const node_type& f, L& lambda) const { - iterate_ast(f.args, lambda); + iterate_ast(f.callArgs, lambda); } }; @@ -15635,6 +15684,7 @@ namespace sqlite_orm { auto result = polyfill::apply(udf, std::move(argsTuple)); statement_binder().result(context, result); }, + /* finalCall = */ nullptr, allocate_udf_storage()); @@ -16592,14 +16642,14 @@ namespace sqlite_orm { struct statement_serializer, void> : statement_serializer, void> {}; - template - struct statement_serializer, void> { - using statement_type = function_call; + template + struct statement_serializer, void> { + using statement_type = function_call; template std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << F::name() << "(" << streaming_expressions_tuple(statement.args, context) << ")"; + ss << F::name() << "(" << streaming_expressions_tuple(statement.callArgs, context) << ")"; return ss.str(); } }; diff --git a/tests/static_tests/function_static_tests.cpp b/tests/static_tests/function_static_tests.cpp index f29092cb4..da78a04d9 100644 --- a/tests/static_tests/function_static_tests.cpp +++ b/tests/static_tests/function_static_tests.cpp @@ -58,7 +58,7 @@ TEST_CASE("function static") { using ExpectedType = double (Function::*)(double) const; STATIC_REQUIRE(std::is_same::value); - using ArgumentsTuple = internal::member_function_arguments::tuple_type; + using ArgumentsTuple = internal::function_arguments; using ExpectedArgumentsTuple = std::tuple; STATIC_REQUIRE(std::is_same::value); @@ -80,7 +80,7 @@ TEST_CASE("function static") { using ExpectedType = double (Function::*)(double); STATIC_REQUIRE(std::is_same::value); - using ArgumentsTuple = internal::member_function_arguments::tuple_type; + using ArgumentsTuple = internal::function_arguments; using ExpectedArgumentsTuple = std::tuple; STATIC_REQUIRE(std::is_same::value); @@ -102,7 +102,7 @@ TEST_CASE("function static") { using ExpectedType = int (Function::*)(std::string) const; STATIC_REQUIRE(std::is_same::value); - using ArgumentsTuple = internal::member_function_arguments::tuple_type; + using ArgumentsTuple = internal::function_arguments; using ExpectedArgumentsTuple = std::tuple; STATIC_REQUIRE(std::is_same::value); @@ -124,7 +124,7 @@ TEST_CASE("function static") { using ExpectedType = int (Function::*)(std::string); STATIC_REQUIRE(std::is_same::value); - using ArgumentsTuple = internal::member_function_arguments::tuple_type; + using ArgumentsTuple = internal::function_arguments; using ExpectedArgumentsTuple = std::tuple; STATIC_REQUIRE(std::is_same::value); @@ -146,7 +146,7 @@ TEST_CASE("function static") { using ExpectedType = std::string (Function::*)(const std::string&, const std::string&) const; STATIC_REQUIRE(std::is_same::value); - using ArgumentsTuple = internal::member_function_arguments::tuple_type; + using ArgumentsTuple = internal::function_arguments; using ExpectedArgumentsTuple = std::tuple; STATIC_REQUIRE(std::is_same::value); @@ -168,7 +168,7 @@ TEST_CASE("function static") { using ExpectedType = std::string (Function::*)(const std::string&, const std::string&); STATIC_REQUIRE(std::is_same::value); - using ArgumentsTuple = internal::member_function_arguments::tuple_type; + using ArgumentsTuple = internal::function_arguments; using ExpectedArgumentsTuple = std::tuple; STATIC_REQUIRE(std::is_same::value);