diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index f67a5a00..8bc2f366 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -55,10 +55,23 @@ namespace chaiscript::dispatch::detail { } } + template + struct is_shared_ptr : std::false_type {}; + + template + struct is_shared_ptr> : std::true_type {}; + template static Boxed_Value box(Q &&q) { + using bare_p = std::remove_cv_t>; if constexpr (std::is_same_v>) { return std::forward(q); + } else if constexpr (is_shared_ptr::value) { + // Pass shared_ptr arguments through by value rather than wrapping a + // reference. Boxed_Value's shared_ptr-aware overloads then record the + // bare type as the pointee, allowing dispatch to a C++ function that + // takes the same shared_ptr on the other side. + return Boxed_Value(bare_p(std::forward(q))); } else if constexpr (std::is_reference_v

) { return Boxed_Value(std::ref(std::forward(q))); } else { diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index 844be6e9..65fd4b6e 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -354,6 +354,29 @@ TEST_CASE("Functor cast") { CHECK(d == 3 * 6); } +namespace { + int shared_ptr_callback_observed_value = 0; + + void shared_ptr_callback_accept(const std::shared_ptr &ptr) { shared_ptr_callback_observed_value = ptr ? *ptr : 0; } + + void shared_ptr_callback_call(const std::function &)> &func) { func(std::make_shared(42)); } +} // namespace + +// Regression for https://github.com/ChaiScript/ChaiScript/issues/493 - shared_ptr +// arguments could not be round-tripped from C++ through a std::function-wrapped +// ChaiScript callback back into a C++ function expecting a shared_ptr. +TEST_CASE("shared_ptr passed through std::function callback") { + chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser()); + + shared_ptr_callback_observed_value = 0; + + chai.add(chaiscript::fun(&shared_ptr_callback_accept), "accept"); + chai.add(chaiscript::fun(&shared_ptr_callback_call), "call"); + + CHECK_NOTHROW(chai.eval("call(accept)")); + CHECK(shared_ptr_callback_observed_value == 42); +} + TEST_CASE("Non-ASCII characters in the middle of string") { chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser()); CHECK_THROWS_AS(chai.eval("prin\xeft \"Hello World\""), chaiscript::exception::eval_error);