-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Create sequences using initializer list #2451
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems useful & harmless to me.
include/pybind11/pytypes.h
Outdated
explicit tuple(std::initializer_list<object> init_list) : tuple(init_list.size()) { | ||
size_t index {0}; | ||
for (const pybind11::object& item : init_list) | ||
detail::tuple_accessor(*this, index++) = item; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this, we could think about deprecating setting elements of a tuple, since tuples are supposed to be immutable once constructed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing for this PR ofc :-)
initializer list.
test_pytypes also checks for new mixed types data returned.
Thanks for the updates, @cowo78! Let's get a few more reviews in, and then this should be able to go in, as far as I'm concerned. |
I would have preferred something more general. Why not allow explicit tuple(std::ranges::forward_range auto&& rng) : tuple(std::ranges::distance(rng)) {
size_t i = 0;
for(object&& o : rng) detail::tuple_accessor(*this, index++) = item;
} Now I know C++20 is really really new, but any thoughts on doing something like that with |
Is there a problem with accepting any |
If you accept any type with |
Ok, right. What I tried to say: I like that idea so much that it would be a pity to only have it on C++20 ;) Would you like to look into this, @cowo78, or should we merge this independently and have @bstaletic set up another PR? (Or @bstaletic could add to this PR, ofc) |
Woo! My #include <type_traits>
#include <iterator>
#include <utility>
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T, typename = void>
struct is_iterable : std::false_type {};
template <typename T>
struct is_iterable<T, void_t<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>>
: std::true_type {};
template <typename T,
typename std::enable_if<is_iterable<T>::value &&
std::is_base_of<std::forward_iterator_tag,
typename std::iterator_traits<typename T::iterator>::iterator_category>::value,
int>::type = 0>
void f(T&&) {}
int main() {
f(std::vector<int>{});
f(std::list<int>{});
f(std::set<int>{});
f(std::initializer_list<int>{});
f(std::map<int,int>{});
//f(pybind11::dict{}); // pybind11 types don't have iterator typedef.
} |
I won't argue about C++-20 since I did not (yet) look into the new features. I will try to provide something that allows using containers whose iterators are forward iterators. Since we're dancing it would be also interesting to construct the containers using heterogeneous types i.e. |
Thanks!
In C++17 that would be something like this: template<typename ...Ts>
tuple(Ts&&... ts) : tuple(sizeof...(Ts)) {
// C++17 fold expressions. C++11 would need some recursive template instantiations and would tank compile times.
size_t index = 0;
(..., (detail::tuple_accessor(*this, index++) = py::cast(std::forward<Ts>(ts))));
} Questions:
Even though the variadic template version is more efficient than an equivalent |
concept (only tuple right now). Provides 3 new constructors: initializer_list<py::object> to use heterogeneous py::objects initializer_list<T> to use homogeneous C++ objects container<T> to use C++ containers that provide a size() method and a forward iterator (see pybind#2451 discussion)
using also py::str. Added tests for WIP container based constructor for tuple.
My 2c:
Yes.
No. We want
Both, so that you have the following options:
Does not hurt to keep both, as it also gives an option to limit binary size. |
Two things:
|
Clarification: by that I mean, we only add a constructor from |
My 2c:
So, yes, stuff is bloating up here. It may very well be that my knowledge is not up to the task but I did not figure out how to do something more compact.
Right, I forgot that. |
Oh, I don't know about that. @bstaletic will, though, I expect @bstaletic?
I don't agree with adding that here, I think. It was also not part of your original proposal.
No, I'm not claiming that. I just want to keep things separated a bit. |
Well, it wasn't in the original proposal just because I used py::object for a start. I just think that both versions are useful. Your shout however.
Again, I'm just a simple user so your shout here. |
Sort of correct. An |
I'm also not the only one going over this, ofc. But here's my suggestion: adapt this PR to @bstaletic's suggestion ( EDIT: What's @bstaletic's take on this? |
This pull request is quickly losing focus and we're getting side-tracked. That aside, I'm not a fan of As for Also, my "any forward range" should probably have a constraint that |
Actually, I'm quickly losing the value of constructing a |
Well, I think one can make use of
The "forward range" concept of course is much better than the constrained "initializer_list" but it seems that you cannot use a templated rvalue constructor with an initializer list. All of this said I think we can go back to a simple question: do we really need an initializer_list constructor since its functionality can basically be achieved with existing |
I'm, again, really not sure it's not
I'm going to pass this to @bstaletic, who tried out more. Can we not achieve this, @bstaletic?
I think it's nice to have a Python-interface to construct from a list of |
based constructor only. Removed all other experimental constructors.
constructors work as expected.
I reverted all other constructor and left only a |
explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen_t{}) { | ||
if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); | ||
} | ||
/** \rst | ||
Creates a ``tuple`` from an initializer list of object instances. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe
Creates a ``tuple`` from an initializer list of object instances. | |
Creates a ``tuple`` from an initializer list of ``py::object`` instances. |
just to be explicit? In addition, the added documentation on make_tuple
in #2840 could be augmented with some remarks on the new ways to initialize a tuple. I didn't bother to document list
and set
there, because they are mutable (pybind11 offers ways to modify tuples, but that's besides the point).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Explicit is better than implicit.
#include <array> | ||
#include <deque> | ||
#include <list> | ||
#include <set> | ||
#include <string> | ||
#include <vector> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#include <array> | |
#include <deque> | |
#include <list> | |
#include <set> | |
#include <string> | |
#include <vector> |
I assume these are leftovers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but leave the #include <string>
as strings are used.
To me it would be useful to be able to construct a few containers (i.e. tuple, list) using initializer lists (see #1669)