mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-06-15 00:16:17 +08:00
The cheatsheet's "preferred" syntax for binding overloaded free functions, fun<Ret(Args...)>(&overloaded), only worked on MSVC because the existing fun<T>(T&&) overload sets T to a function type when called explicitly, which produces a function rvalue-reference parameter that does not match a function pointer argument. Standards-conforming compilers (clang, GCC in some modes) correctly rejected it. Added two new fun overloads, parameterized on the explicitly-supplied function-type Signature and using std::type_identity_t to keep that parameter non-deducible, so they only participate in overload resolution when Signature is given explicitly. One accepts a free function pointer, the other a pointer-to-member, enabling both fun<Ret(Args...)>(&free_fn) and fun<Ret(Args...) cv>(&Class::method) to disambiguate overloads without resorting to static_cast. Co-authored-by: leftibot <leftibot@users.noreply.github.com>
This commit is contained in:
parent
85b8e7c0c8
commit
d60f8fed73
@ -82,6 +82,43 @@ namespace chaiscript {
|
||||
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from an overloaded free function, with the
|
||||
/// signature specified explicitly to disambiguate the overload.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// int overloaded(int);
|
||||
/// double overloaded(double);
|
||||
///
|
||||
/// chai.add(chaiscript::fun<int(int)>(&overloaded), "overloaded");
|
||||
/// chai.add(chaiscript::fun<double(double)>(&overloaded), "overloaded");
|
||||
/// \endcode
|
||||
template<typename Sig, std::enable_if_t<std::is_function_v<Sig>, int> = 0>
|
||||
Proxy_Function fun(std::type_identity_t<Sig> *f) {
|
||||
return dispatch::detail::make_callable(f, dispatch::detail::function_signature(f));
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from an overloaded member function, with the
|
||||
/// signature specified explicitly to disambiguate the overload.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// class MyClass {
|
||||
/// public:
|
||||
/// int overloaded(int);
|
||||
/// double overloaded(double);
|
||||
/// int const_overloaded() const;
|
||||
/// };
|
||||
///
|
||||
/// chai.add(chaiscript::fun<int(int)>(&MyClass::overloaded), "overloaded");
|
||||
/// chai.add(chaiscript::fun<double(double)>(&MyClass::overloaded), "overloaded");
|
||||
/// chai.add(chaiscript::fun<int() const>(&MyClass::const_overloaded), "const_overloaded");
|
||||
/// \endcode
|
||||
template<typename Sig, typename Class, std::enable_if_t<std::is_function_v<Sig>, int> = 0>
|
||||
Proxy_Function fun(std::type_identity_t<Sig> Class::*f) {
|
||||
return dispatch::detail::make_callable(f, dispatch::detail::function_signature(f));
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
||||
/// \param[in] t Function / member to expose
|
||||
/// \param[in] q Value to bind to first parameter
|
||||
|
||||
@ -581,6 +581,74 @@ TEST_CASE("Utility_Test utility class wrapper") {
|
||||
chai.eval("t = Utility_Test();");
|
||||
}
|
||||
|
||||
///// Issue 612: fun<Sig>(&overloaded) should work for free and member function overloads
|
||||
|
||||
namespace issue_612 {
|
||||
std::string free_overload(int) { return "int"; }
|
||||
std::string free_overload(double) { return "double"; }
|
||||
std::string free_overload(const std::string &, bool) { return "string,bool"; }
|
||||
|
||||
class Issue_612_Class {
|
||||
public:
|
||||
std::string member_overload(int) { return "int"; }
|
||||
std::string member_overload(double) { return "double"; }
|
||||
std::string const_member_overload(int) const { return "const_int"; }
|
||||
std::string const_member_overload(double) const { return "const_double"; }
|
||||
};
|
||||
} // namespace issue_612
|
||||
|
||||
TEST_CASE("Issue 612: fun<Signature> for overloaded free functions") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::fun<std::string(int)>(&issue_612::free_overload), "free_overload");
|
||||
chai.add(chaiscript::fun<std::string(double)>(&issue_612::free_overload), "free_overload");
|
||||
chai.add(chaiscript::fun<std::string(const std::string &, bool)>(&issue_612::free_overload), "free_overload");
|
||||
|
||||
CHECK(chai.eval<std::string>("free_overload(1)") == "int");
|
||||
CHECK(chai.eval<std::string>("free_overload(1.5)") == "double");
|
||||
CHECK(chai.eval<std::string>("free_overload(\"hi\", true)") == "string,bool");
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 612: fun<Signature> for overloaded member functions (pointer-to-member form)") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::user_type<issue_612::Issue_612_Class>(), "Issue_612_Class");
|
||||
chai.add(chaiscript::constructor<issue_612::Issue_612_Class()>(), "Issue_612_Class");
|
||||
|
||||
chai.add(chaiscript::fun<std::string (issue_612::Issue_612_Class::*)(int)>(&issue_612::Issue_612_Class::member_overload),
|
||||
"member_overload");
|
||||
chai.add(chaiscript::fun<std::string (issue_612::Issue_612_Class::*)(double)>(&issue_612::Issue_612_Class::member_overload),
|
||||
"member_overload");
|
||||
chai.add(chaiscript::fun<std::string (issue_612::Issue_612_Class::*)(int) const>(&issue_612::Issue_612_Class::const_member_overload),
|
||||
"const_member_overload");
|
||||
chai.add(chaiscript::fun<std::string (issue_612::Issue_612_Class::*)(double) const>(&issue_612::Issue_612_Class::const_member_overload),
|
||||
"const_member_overload");
|
||||
|
||||
chai.eval("var t = Issue_612_Class();");
|
||||
CHECK(chai.eval<std::string>("t.member_overload(1)") == "int");
|
||||
CHECK(chai.eval<std::string>("t.member_overload(1.5)") == "double");
|
||||
CHECK(chai.eval<std::string>("t.const_member_overload(1)") == "const_int");
|
||||
CHECK(chai.eval<std::string>("t.const_member_overload(1.5)") == "const_double");
|
||||
}
|
||||
|
||||
TEST_CASE("Issue 612: fun<Signature> for overloaded member functions (function-type form)") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::user_type<issue_612::Issue_612_Class>(), "Issue_612_Class");
|
||||
chai.add(chaiscript::constructor<issue_612::Issue_612_Class()>(), "Issue_612_Class");
|
||||
|
||||
chai.add(chaiscript::fun<std::string(int)>(&issue_612::Issue_612_Class::member_overload), "member_overload");
|
||||
chai.add(chaiscript::fun<std::string(double)>(&issue_612::Issue_612_Class::member_overload), "member_overload");
|
||||
chai.add(chaiscript::fun<std::string(int) const>(&issue_612::Issue_612_Class::const_member_overload), "const_member_overload");
|
||||
chai.add(chaiscript::fun<std::string(double) const>(&issue_612::Issue_612_Class::const_member_overload), "const_member_overload");
|
||||
|
||||
chai.eval("var t = Issue_612_Class();");
|
||||
CHECK(chai.eval<std::string>("t.member_overload(1)") == "int");
|
||||
CHECK(chai.eval<std::string>("t.member_overload(1.5)") == "double");
|
||||
CHECK(chai.eval<std::string>("t.const_member_overload(1)") == "const_int");
|
||||
CHECK(chai.eval<std::string>("t.const_member_overload(1.5)") == "const_double");
|
||||
}
|
||||
|
||||
enum Utility_Test_Numbers {
|
||||
ONE,
|
||||
TWO,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user