Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ambiguous initialize_list arguments #822

Merged
merged 1 commit into from
Apr 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/pybind11/buffer_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = true)
: buffer_info(view->buf, (size_t) view->itemsize, view->format, (size_t) view->ndim,
Expand Down
5 changes: 0 additions & 5 deletions include/pybind11/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -686,11 +686,6 @@ class any_container {
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)) { }

Expand Down
17 changes: 10 additions & 7 deletions include/pybind11/numpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ class array : public buffer {
forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_
};

array() : array(0, static_cast<const double *>(nullptr)) {}
array() : array({{0}}, static_cast<const double *>(nullptr)) {}

using ShapeContainer = detail::any_container<Py_intptr_t>;
using StridesContainer = detail::any_container<Py_intptr_t>;
Expand Down Expand Up @@ -499,12 +499,9 @@ class array : public buffer {
array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle())
: array(dt, std::move(shape), {}, 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, typename = detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>
array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle())
: array(dt, {{count}}, ptr, base) { }

template <typename T>
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
Expand All @@ -514,6 +511,9 @@ class array : public buffer {
array(ShapeContainer shape, const T *ptr, handle base = handle())
: array(std::move(shape), {}, ptr, base) { }

template <typename T>
explicit 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) { }

Expand Down Expand Up @@ -738,6 +738,9 @@ template <typename T, int ExtraFlags = array::forcecast> class array_t : 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);
}
Expand Down
6 changes: 6 additions & 0 deletions tests/test_numpy_array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,10 @@ test_initializer numpy_array([](py::module &m) {
// Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object:
sm.def("array_fail_test", []() { return py::array(py::object()); });
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });

// Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
sm.def("array_initializer_list", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2 }); });
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2, 3 }); });
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2, 3, 4 }); });
});