PrevUpHomeNext

class bound_function

primer::bound_function is a primer::lua_ref which is known to point to an object of function type.

bound_function provides several handy methods for calling the function, passing in one or several C++ objects, and obtaining the result as (one or several) primer::lua_ref. These objects are pushed onto the lua stack using primer::push, then the bound function is invoked using pcall. Any errors are returned to the caller -- the lua stack is always unchanged by this operation at the end.

primer::bound_function can be used to create C++ function objects referring to a function implemented in lua.

These objects are safe -- calling them does not raise exceptions, and they handle any lua errors and return them as primer::error objects, even if the user function errs or the lua VM is destroyed. Furthermore, they carry out an appropriate call to lua_checkstack no matter what parameters they are passed for the call.

The idea is that you should be able to pass these to other parts of a C++ program that don't have anything to do with lua, and use them like generic function objects without having to mentally switch context and think about lua preconditions and such.

[Caution] Caution

Like lua_ref, these objects are not thread-safe.

primer::bound_function can also be used to create a primer::coroutine.

Synopsis
class bound_function {
  lua_ref ref_;

public:
  // Special member functions
  bound_function() noexcept = default;
  bound_function(const bound_function &) = default;
  bound_function(bound_function &&) noexcept = default;
  bound_function & operator=(const bound_function &) = default;
  bound_function & operator=(bound_function &&) noexcept = default;
  ~bound_function() noexcept = default;

  // Primary constructor: Bind to a function on top of the stack.
  // Only capture the top item if it is actually a function.
  // Pop the item *whether or not* it is a function.
  1explicit bound_function(lua_State * L);

  // Forwarded methods from lua_ref
  explicit operator bool() const noexcept { return static_cast<bool>(ref_); }

  lua_State * lock() const noexcept { return ref_.lock(); }
  lua_State * push() const noexcept { return ref_.push(); }
  bool push(lua_State * L) const noexcept { return ref_.push(L); }
  void reset() noexcept { ref_.reset(); }
  void swap(bound_function & other) noexcept { ref_.swap(other.ref_); }

  // Call methods
  // These methods attempt to lock the state which holds the lua function,
  // and perform the call there. They clean up after themselves and leave the
  // stack as they found it afterwards.
  //
  // If passed a lua_ref_seq, its members are the call arguments. If passed
  // any other sequence of C++ types, those objects are pushed onto the stack
  // and are the call arguments.

  template <typename... Args>
  expected<void> call_no_ret(Args &&... args) const noexcept;
  expected<void> call_no_ret(lua_ref_seq &) const noexcept;
  expected<void> call_no_ret(lua_ref_seq const &) const noexcept;
  expected<void> call_no_ret(lua_ref_seq &&) const noexcept;

  template <typename... Args>
  expected<lua_ref> call_one_ret(Args &&... args) const noexcept;
  expected<lua_ref> call_one_ret(lua_ref_seq &) const noexcept;
  expected<lua_ref> call_one_ret(lua_ref_seq const &) const noexcept;
  expected<lua_ref> call_one_ret(lua_ref_seq &&) const noexcept;

  template <typename... Args>
  expected<lua_ref_seq> call(Args &&... args) const noexcept;
  expected<lua_ref_seq> call(lua_ref_seq &) const noexcept;
  expected<lua_ref_seq> call(lua_ref_seq const &) const noexcept;
  expected<lua_ref_seq> call(lua_ref_seq &&) const noexcept;

  // Get a debug string describing what function is bound
  // Uses lua debug api
  std::string debug_string() const;
};

1

Note: Can cause lua memory allocation failure from ref_ ctor.

Read / Push semantics

Similar to lua_ref, these can be pushed onto the stack by primer::push.

On read, the nil value is read as putting the bound_function into the empty state. Otherwise, if it's a function, it is bound, and anything else causes an error.


PrevUpHomeNext