mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
Make keyword argument hold a py::object instead of T*
With this change arg_t is no longer a template, but it must remain so for backward compatibility. Thus, a non-template arg_v is introduced, while a dummy template alias arg_t is there to keep old code from breaking. This can be remove in the next major release. The implementation of arg_v also needed to be placed a little earlier in the headers because it's not a template any more and unpacking_collector needs more than a forward declaration.
This commit is contained in:
parent
8fe13b8896
commit
60b26802fd
@ -14,30 +14,6 @@
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
|
||||
/// Annotation for keyword arguments
|
||||
struct arg {
|
||||
constexpr explicit arg(const char *name) : name(name) { }
|
||||
|
||||
template <typename T>
|
||||
constexpr arg_t<T> operator=(const T &value) const { return {name, value}; }
|
||||
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/// Annotation for keyword arguments with default values
|
||||
template <typename T> struct arg_t : public arg {
|
||||
constexpr arg_t(const char *name, const T &value, const char *descr = nullptr)
|
||||
: arg(name), value(&value), descr(descr) { }
|
||||
|
||||
const T *value;
|
||||
const char *descr;
|
||||
};
|
||||
|
||||
inline namespace literals {
|
||||
/// String literal version of arg
|
||||
constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
|
||||
}
|
||||
|
||||
/// Annotation for methods
|
||||
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
|
||||
|
||||
@ -233,21 +209,14 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
||||
};
|
||||
|
||||
/// Process a keyword argument attribute (*with* a default value)
|
||||
template <typename T>
|
||||
struct process_attribute<arg_t<T>> : process_attribute_default<arg_t<T>> {
|
||||
static void init(const arg_t<T> &a, function_record *r) {
|
||||
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
||||
static void init(const arg_v &a, function_record *r) {
|
||||
if (r->class_ && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr, handle());
|
||||
|
||||
/* Convert keyword value into a Python object */
|
||||
auto o = object(detail::make_caster<T>::cast(
|
||||
*a.value, return_value_policy::automatic, handle()), false);
|
||||
|
||||
if (!o) {
|
||||
if (!a.value) {
|
||||
#if !defined(NDEBUG)
|
||||
std::string descr(typeid(T).name());
|
||||
detail::clean_type_id(descr);
|
||||
descr = "'" + std::string(a.name) + ": " + descr + "'";
|
||||
auto descr = "'" + std::string(a.name) + ": " + a.type + "'";
|
||||
if (r->class_) {
|
||||
if (r->name)
|
||||
descr += " in method '" + (std::string) r->class_.str() + "." + (std::string) r->name + "'";
|
||||
@ -264,7 +233,7 @@ struct process_attribute<arg_t<T>> : process_attribute_default<arg_t<T>> {
|
||||
"Compile in debug mode for more information.");
|
||||
#endif
|
||||
}
|
||||
r->args.emplace_back(a.name, a.descr, o.release());
|
||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -949,6 +949,44 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Annotation for keyword arguments
|
||||
struct arg {
|
||||
constexpr explicit arg(const char *name) : name(name) { }
|
||||
template <typename T> arg_v operator=(T &&value) const;
|
||||
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/// Annotation for keyword arguments with values
|
||||
struct arg_v : arg {
|
||||
template <typename T>
|
||||
arg_v(const char *name, T &&x, const char *descr = nullptr)
|
||||
: arg(name),
|
||||
value(detail::make_caster<T>::cast(x, return_value_policy::automatic, handle()), false),
|
||||
descr(descr)
|
||||
#if !defined(NDEBUG)
|
||||
, type(type_id<T>())
|
||||
#endif
|
||||
{ }
|
||||
|
||||
object value;
|
||||
const char *descr;
|
||||
#if !defined(NDEBUG)
|
||||
std::string type;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
arg_v arg::operator=(T &&value) const { return {name, std::forward<T>(value)}; }
|
||||
|
||||
/// Alias for backward compatibility -- to be remove in version 2.0
|
||||
template <typename /*unused*/> using arg_t = arg_v;
|
||||
|
||||
inline namespace literals {
|
||||
/// String literal version of arg
|
||||
constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
|
||||
}
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
NAMESPACE_BEGIN(constexpr_impl)
|
||||
/// Implementation details for constexpr functions
|
||||
@ -1044,8 +1082,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void process(list &/*args_list*/, arg_t<T> &&a) {
|
||||
void process(list &/*args_list*/, arg_v a) {
|
||||
if (m_kwargs[a.name]) {
|
||||
#if defined(NDEBUG)
|
||||
multiple_values_error();
|
||||
@ -1053,15 +1090,14 @@ private:
|
||||
multiple_values_error(a.name);
|
||||
#endif
|
||||
}
|
||||
auto o = object(detail::make_caster<T>::cast(*a.value, policy, nullptr), false);
|
||||
if (!o) {
|
||||
if (!a.value) {
|
||||
#if defined(NDEBUG)
|
||||
argument_cast_error();
|
||||
#else
|
||||
argument_cast_error(a.name, type_id<T>());
|
||||
argument_cast_error(a.name, a.type);
|
||||
#endif
|
||||
}
|
||||
m_kwargs[a.name] = o;
|
||||
m_kwargs[a.name] = a.value;
|
||||
}
|
||||
|
||||
void process(list &/*args_list*/, detail::kwargs_proxy kp) {
|
||||
|
@ -17,7 +17,7 @@ NAMESPACE_BEGIN(pybind11)
|
||||
|
||||
/* A few forward declarations */
|
||||
class object; class str; class iterator;
|
||||
struct arg; template <typename T> struct arg_t;
|
||||
struct arg; struct arg_v;
|
||||
namespace detail { class accessor; class args_proxy; class kwargs_proxy; }
|
||||
|
||||
/// Holds a reference to a Python object (no reference counting)
|
||||
|
Loading…
Reference in New Issue
Block a user