mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
Fix #493: Allow shared_ptr arguments through std::function callbacks
When ChaiScript wraps a script function in a C++ std::function whose parameter is a shared_ptr (e.g. const std::shared_ptr<T> &), the Build_Function_Caller_Helper boxed each argument with std::ref. That produced a Boxed_Value whose Any held a reference_wrapper<const shared_ptr<T>> with bare type info shared_ptr<T> instead of T, so dispatch to a C++ function expecting shared_ptr<T> failed. Detect shared_ptr parameter types in box() and store them by value instead, letting Boxed_Value's shared_ptr-aware overloads record the correct bare type and back the Any with a real shared_ptr. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
56506bc111
commit
9db4a88b99
@ -55,10 +55,23 @@ namespace chaiscript::dispatch::detail {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct is_shared_ptr : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
|
||||
|
||||
template<typename P, typename Q>
|
||||
static Boxed_Value box(Q &&q) {
|
||||
using bare_p = std::remove_cv_t<std::remove_reference_t<P>>;
|
||||
if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) {
|
||||
return std::forward<Q>(q);
|
||||
} else if constexpr (is_shared_ptr<bare_p>::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<T> on the other side.
|
||||
return Boxed_Value(bare_p(std::forward<Q>(q)));
|
||||
} else if constexpr (std::is_reference_v<P>) {
|
||||
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||
} else {
|
||||
|
||||
@ -355,6 +355,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<int> &ptr) { shared_ptr_callback_observed_value = ptr ? *ptr : 0; }
|
||||
|
||||
void shared_ptr_callback_call(const std::function<void(const std::shared_ptr<int> &)> &func) { func(std::make_shared<int>(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<std::string>("prin\xeft \"Hello World\""), chaiscript::exception::eval_error);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user