Create sequences using initializer list#2451
Conversation
YannickJadoul
left a comment
There was a problem hiding this comment.
Seems useful & harmless to me.
| 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.
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.
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 |
| 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.
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.
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.
| #include <array> | |
| #include <deque> | |
| #include <list> | |
| #include <set> | |
| #include <string> | |
| #include <vector> |
I assume these are leftovers?
There was a problem hiding this comment.
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)