-
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
Fix stl_bind to support movable, non-copyable value types #490
Conversation
Thanks, that's a good catch. I think I prefer the approach from stackoverflow which defines a custom version of |
ITYM |
eb5852f
to
644fe67
Compare
Added the same support for non-copyable map types (and rewrote the commit history to squash and split up commits).
That's basically the approach here, except the specialization is right along with the general case, using one specialization that should work for any stl container types. Putting the override in We also can't just list it for all stl types, because there are stl types like The implementation in this PR seems to have a pretty negligible cost, though (comparing to current master):
... and now I'll go fix the build failure :) |
This removes some unncessary extra template parameters and parameter packs, making the logic a bit simpler.
make_copy_constructor currently fails for various stl containers (e.g. std::vector, std::unordered_map, std::deque, etc.) when the container's value type (e.g. the "T" or the std::pair<K,T> for a map) is non-copyable. This adds an override that, for types that look like containers, also requires that the value_type be copyable.
Most stl_bind modifiers require copying, so if the type isn't copy constructible, we provide a read-only interface instead. In practice, this means that if the type is non-copyable, it will be, for all intents and purposes, read-only from the Python side (but currently it simply fails to compile with such a container). It is still possible for the caller to provide an interface manually (by defining methods on the returned class_ object), but this isn't something stl_bind can handle because the C++ code to construct values is going to be highly dependent on the container value_type.
2c78e59
to
378debb
Compare
Fixed and squashed. |
A thought while reading through the diff -- some of this may also be related to the prior implementation: I wonder if the vector getitem for the is_copy_constructible case makes sense: it always creates a copy. This could be undesirable if the value_type is a heap-allocated type bound with |
template <typename Container> struct is_copy_constructible<Container, enable_if_t< | ||
std::is_copy_constructible<Container>::value && | ||
std::is_same<typename Container::value_type &, typename Container::reference>::value | ||
>> : std::is_copy_constructible<typename Container::value_type> {}; |
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.
Nifty :)
Sounds good to me. One problem, though: making them both return by reference almost works, but breaks the |
For non-primitive types, we may well be copying some complex type, when returning by reference is more appropriate. This commit returns by internal reference for all but basic arithmetic types.
Sorry, one more change request that I didn't realize before: there duplication between cases which return a reference & use the return value policy I think that you can always use the first case even for arithmetic types. In that case, an arithmetic This will allow to remove some duplication & make for easier reading. |
Unfortunately not for bool: The two different map versions, on the other hand, can be eliminated. |
Only if we definitely can't--i.e. std::vector<bool>--becasue v[i] returns something that isn't a T& do we copy; for everything else, we return by reference. For the map case, we can always return by reference (at least for the default stl map/unordered_map).
Updated to use references whenever possible; the special copying case for vectors is now only relied on if |
LGTM, thanks! |
Fixes #487 (but not ready for merging).
We require copyable types for pretty much all vector modifiers, so this basically moves them all into a method that is only enabled for copyable types. (Technically we could allow
pop
and__delitem__
without copying, but it seems a little weird to expose deletion but no other modifiers).In practice, this means that if the type is non-copyable, it will be, for all intents and purposes, readonly from the Python side--but at least it's something (currently it fails to compile).
This is still incomplete: it needs similar support for bind_map, and needs a better solution for the current dirty hack in
cast.h
, on which I'd appreciate input on how to deal with it. I definitely don't think it should remain as is: this was just a hack to get it working as a starting point.The issue is that
make_copy_constructor
fails forstd::vector<vt>
wherevt
is non-copyable. Thedecltype(new std::vector<vt>(...))
succeeds (i.e. is a type), but an actual attempt to invoke the constructor results in a compilation failure. (std::is_copy_constructible
also fails in the same way, i.e. by returning true even when actually invoking the copy constructor results in a compilation failure). For now I'm just hacking around it (and the hack is only on the non-MSVC path: the MSVC build of this will fail), but a better solution is needed. @AlZie (in #487) points to a workaround in http://stackoverflow.com/questions/18404108/issue-with-is-copy-constructible; any thoughts on something better?