Make any_container implicitly constructible from arithmetic values

This further reduces the constructors required in buffer_info/numpy by
removing the need for the constructors that take a single size_t and
just forward it on via an initializer_list to the container-accepting
constructor.

Unfortunately, in `array` one of the constructors runs into an ambiguity
problem with the deprecated `array(handle, bool)` constructor (because
both the bool constructor and the any_container constructor involve an
implicit conversion, so neither has precedence), so a forwarding
constructor is kept there (until the deprecated constructor is
eventually removed).
This commit is contained in:
Jason Rhinelander 2017-04-12 18:35:46 -04:00
parent 5f38386293
commit 201796d94f
3 changed files with 15 additions and 13 deletions

View File

@ -36,7 +36,7 @@ struct buffer_info {
}
buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t size)
: buffer_info(ptr, itemsize, format, 1, { size }, { itemsize }) { }
: buffer_info(ptr, itemsize, format, 1, size, itemsize) { }
explicit buffer_info(Py_buffer *view, bool ownview_in = true)
: buffer_info(view->buf, (size_t) view->itemsize, view->format, (size_t) view->ndim,

View File

@ -660,7 +660,8 @@ static constexpr auto const_ = std::true_type{};
NAMESPACE_BEGIN(detail)
// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from
// any standard container (or C-style array) supporting std::begin/std::end.
// any standard container (or C-style array) supporting std::begin/std::end, any singleton
// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair.
template <typename T>
class any_container {
std::vector<T> v;
@ -680,6 +681,11 @@ public:
template <typename TIn, typename = enable_if_t<std::is_convertible<TIn, T>::value>>
any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) { }
// Implicit conversion constructor from any arithmetic type (only participates if T is also
// arithmetic).
template <typename TIn, typename = enable_if_t<std::is_arithmetic<T>::value && std::is_arithmetic<TIn>::value>>
any_container(TIn singleton) : v(1, static_cast<T>(singleton)) { }
// Avoid copying if given an rvalue vector of the correct type.
any_container(std::vector<T> &&v) : v(std::move(v)) { }

View File

@ -463,7 +463,7 @@ public:
const void *ptr = nullptr, handle base = handle()) {
if (strides->empty())
strides = default_strides(*shape, dt.itemsize());
*strides = default_strides(*shape, dt.itemsize());
auto ndim = shape->size();
if (ndim != strides->size())
@ -499,9 +499,12 @@ public:
array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle())
: array(dt, std::move(shape), {}, ptr, base) { }
array(const pybind11::dtype &dt, size_t count, const void *ptr = nullptr,
handle base = handle())
: array(dt, ShapeContainer{{ count }}, ptr, base) { }
// This constructor is only needed to avoid ambiguity with the deprecated (handle, bool)
// constructor that comes from PYBIND11_OBJECT_CVT; once that is gone, the above constructor can
// handle it (because ShapeContainer is implicitly constructible from arithmetic types)
template <typename T, typename = detail::enable_if_t<std::is_arithmetic<T>::value && !std::is_same<bool, T>::value>>
array(const pybind11::dtype &dt, T count)
: array(dt, count, nullptr) { }
template <typename T>
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
@ -511,10 +514,6 @@ public:
array(ShapeContainer shape, const T *ptr, handle base = handle())
: array(std::move(shape), {}, ptr, base) { }
template <typename T>
array(size_t count, const T *ptr, handle base = handle())
: array({{ count }}, ptr, base) { }
explicit array(const buffer_info &info)
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { }
@ -739,9 +738,6 @@ public:
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
: array(std::move(shape), ptr, base) { }
explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle())
: array(count, ptr, base) { }
constexpr size_t itemsize() const {
return sizeof(T);
}