diff --git a/sol/function.hpp b/sol/function.hpp index 47100c16..7f939412 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -27,6 +27,7 @@ #include "stack.hpp" #include "function_types.hpp" #include "userdata_traits.hpp" +#include "resolve.hpp" #include #include #include diff --git a/sol/resolve.hpp b/sol/resolve.hpp new file mode 100644 index 00000000..201223e8 --- /dev/null +++ b/sol/resolve.hpp @@ -0,0 +1,95 @@ +// The MIT License (MIT) + +// Copyright (c) 2013 Danny Y., Rapptz + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SOL_RESOLVE_HPP +#define SOL_RESOLVE_HPP + +#include "traits.hpp" +#include "tuple.hpp" + +namespace sol { +namespace detail { +template( Args... )>::type> +auto resolve_i( types, F&& )->R( Unqualified::* )( Args... ) { + typedef R( Sig )( Args... ); + typedef Unqualified Fu; + return static_cast( &Fu::operator() ); +} + +template +auto resolve_f( std::true_type, F&& f ) -> decltype( resolve_i( types::operator() )>>( ), std::forward( f ) ) ) { + typedef Unqualified Fu; + return resolve_i( types>( ), std::forward( f ) ); +} + +template +void resolve_f( std::false_type, F&& f ) { + static_assert( has_deducible_signature::value, "Cannot use no-template-parameter call with an overloaded functor: specify the signature" ); +} + +template +auto resolve_i( types<>, F&& f ) -> decltype( resolve_f( has_deducible_signature> {}, std::forward( f ) ) ) { + return resolve_f( has_deducible_signature> {}, std::forward( f ) ); +} + +template::type> +auto resolve_i( types, F&& f ) -> decltype( resolve_i( types( ), std::forward( f ) ) ) { + return resolve_i( types( ), std::forward( f ) ); +} + +template +Sig C::* resolve_v( std::false_type, Sig C::* mem_func_ptr ) { + return mem_func_ptr; +} + +template +Sig C::* resolve_v( std::true_type, Sig C::* mem_variable_ptr ) { + return mem_variable_ptr; +} +} // detail + +template +auto resolve( R fun_ptr( Args... ) ) -> R( *)( Args... ) { + return fun_ptr; +} + +template +Sig* resolve( Sig* fun_ptr ) { + return fun_ptr; +} + +template +auto resolve( R( C::*mem_ptr )( Args... ) ) -> R( C::* )( Args... ) { + return mem_ptr; +} + +template +Sig C::* resolve( Sig C::* mem_ptr ) { + return detail::resolve_v( std::is_member_object_pointer( ), mem_ptr ); +} + +template +auto resolve( F&& f ) -> decltype( detail::resolve_i( types( ), std::forward( f ) ) ) { + return detail::resolve_i( types( ), std::forward( f ) ); +} +} // sol + +#endif // SOL_RESOLVE_HPP diff --git a/sol/traits.hpp b/sol/traits.hpp index b5a00e1b..b7d93abc 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -145,6 +145,24 @@ struct is_function_impl { }; } // detail +namespace detail { +template +struct check_deducible_signature { + template + static auto test( int ) -> decltype( &G::operator(), void( ) ); + template + static auto test( ... ) -> struct nat; + + using type = std::is_void < decltype( test( 0 ) ) > ; +}; +} // detail + +template +struct has_deducible_signature : detail::check_deducible_signature::type { }; + +template +using has_deducible_signature_t = typename has_deducible_signature::type; + template struct Function : Bool::value> {}; diff --git a/tests.cpp b/tests.cpp index 47106ed6..2ba10078 100644 --- a/tests.cpp +++ b/tests.cpp @@ -410,17 +410,26 @@ TEST_CASE("functions/overloaded", "Check if overloaded function resolution templ lua.set_function("non_overloaded", non_overloaded); REQUIRE_NOTHROW(lua.script("x = non_overloaded(1)\nprint(x)")); + /* + // Cannot reasonably support: clang++ refuses to try enough + // deductions to make this work lua.set_function("overloaded", overloaded); REQUIRE_NOTHROW(lua.script("print(overloaded(1))")); lua.set_function("overloaded", overloaded); REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))")); + lua.set_function("overloaded", overloaded); + REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))")); + */ + lua.set_function("overloaded", overloaded); + REQUIRE_NOTHROW(lua.script("print(overloaded(1))")); + lua.set_function("overloaded", overloaded); REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))")); - lua.set_function("overloaded", overloaded); - REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))")); + lua.set_function("overloaded", overloaded); + REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))")); } TEST_CASE("functions/return_order_and_multi_get", "Check if return order is in the same reading order specified in Lua") {