Uh oh!
There was an error while loading. Please reload this page.
Do not derive enum_ from class_ - #837
Conversation
5cad257 to
11b8d13Compare| /// Add an enumeration entry | ||
| enum_& value(char const* name, Type value) { | ||
| enum_ value(char const* name, Type value) && { |
There was a problem hiding this comment.
Why only rvalues? I'm a bit more worried about this breaking backward compatibility than the inherited class_ functions.
There was a problem hiding this comment.
Well, if you return a reference, you won't be able to call .into_class() which needs an rvalue (which is an important point, in order to avoid all kinds of edge cases). Taking an rvalue *this here, disabling copy ctor and returning by value basically helps ensure we never copy it (accidentally or not) and always move. The usual chaining-style enum definitions still all work as expected.
There was a problem hiding this comment.
Ah, right, it would be required for the new enum34. I was only looking at it for the enum_ here, which does not need to return an rvalue.
There was a problem hiding this comment.
I've added back the lvalue overloads which seems to work and won't break backwards compatibility if someone chose to assign enum object to a variable and not chain the calls:
// okauto e = enum_<>();
e.value().value();
// ok
enum_<>().value().into_class().def();
// not okauto e = enum_<>().value();
e.into_class().def(); // <-- compile fail// not ok eitherauto e = enum_<>().value();
e.value().into_class().def(); // <-- compile fail| return cls; | ||
| } | ||
| operator class_<Type>() && { |
There was a problem hiding this comment.
Why make it implicitly convertible?
There was a problem hiding this comment.
That's how I had it initially (in the other PR) -- with hindsight, this could probably be removed.
dean0x7d
commented
May 8, 2017
Just to make sure we don't break anything important, I'll just cc this for others how have also contributed to The gist is that |
11b8d13 to
9f06964CompareThinking a bit more about this, I find problematic that Why are we changing this? It seems to be making things more difficult that were simpler before. In that case, I would find it preferable to document the old behavior and keep it as is. |
@wjakob I've initially chosen We are changing it because it was a bit broken initially (and undocumented) since |
I think that it would be straightforward to fix the |
wjakob
commented
May 8, 2017
(i.e. no CRTP needed) |
aldanor
commented
May 8, 2017
Sort of, yea. It's a bit more than def though... |
aldanor
commented
May 8, 2017
(For the CRTP example, see cf1ef95) |
wjakob
commented
May 8, 2017
This seems fine to me -- ~9-ish lines of code that will all be optimized away, no? |
That's it, no? template <typename... Args> def(Args&&... args) { return (enum_&) Base::def(std::forward<Args>(args)...); }
template <typename... Args> def_property_readonly(Args&&... args) { return (enum_&) Base::def_property_readonly(std::forward<Args>(args)...); }
template <typename... Args> def_readonly_static(Args&&... args) { return (enum_&) Base::def_readonly_static(std::forward<Args>(args)...); }Or am I missing something? |
For the new enum34 implementation - yea, something like this (x3) would work; hacky but should suffice. For If we're going this way... this is exactly what a separate CRTP would do, less the copy/paste. With a bit of effort I think it could benefit both enum implementations -- for |
wjakob
commented
May 8, 2017
I don't think it's hacky :). CRTP brings its own set of issues -- it definitely doesn't make the source easier to read ;). In one of my current projects, MSVC 2017 needs to be spoon-fed some of the CRTP-related type aliases to avoid compiler segfaults (accessing members of the derived class in template default parameters still seems somewhat fragile). |
wjakob
commented
May 8, 2017
If the duplication bothers you, we could add a macro: #definePYBIND11_FORWARD(name) template <typename... Args> name(Args&&... args) { returnstatic_cast<decltype(*this)>(Base::name(std::forward<Args>(args)...)); }I'd really prefer this to making something that should be a |
aldanor
commented
May 8, 2017
A macro would be reasonable, it will certainly deal with |
aldanor
commented
May 8, 2017
jagerman
commented
May 8, 2017
Could |
aldanor
commented
May 8, 2017
Btw @wjakob could you post examples of code you've have that relies on |
aldanor
commented
May 8, 2017
@jagerman I was thinking about it too, will take a look tomorrow. |
wjakob
commented
May 8, 2017
One simple example are cases where an enumeration exists in separate classes. Something like this: classA {
enum E {Value = 0};
};
classB {
using E = A::E;
};
class_<A> cls_a(m, "A");
class_<B> cls_b(m, "B");
enum_<A::E> e(cls_a, "E");
e.value("Value", A::E::Value);
cls_b.attr("E") = e; |
aldanor
commented
May 8, 2017
wjakob
commented
May 8, 2017
Hm -- what about @jagerman's suggestion ( |
I thought a little bit about it and don't think |
jagerman
commented
May 8, 2017
I'm not sure I see the problem with the |
aldanor
commented
May 8, 2017
@jagerman Hmm yea you're right, in the current state |
jagerman
commented
May 9, 2017
... nor will @wjakob's if the lvalue version is removed, which doesn't seem desirable. Requiring you to write |
Yep, you're right. Either way something will be broken it seems :) Unless there's some other, smarter way (deriving from object but not class_? idk). If there's no middle ground, I'm ok with retracting this PR altogether since it was opened out of a suggestion voiced in enum34 PR. if everyone thinks the |
dean0x7d
commented
Jun 25, 2017
I guess the entire point here was to make |
aldanor
commented
Jun 25, 2017
Yea; far as I see now, without big changes it's only possible to make them API compatible if we accept the possibility of runtime errors thrown in enum34 API at module initialization time due to incorrect use (which gets compiled ok) -- I really wouldn't like this to be the case. So (soon as I get back to IE...) I'll probably close this and revert all changes to |
aldanor
commented
Jun 25, 2017
In fact I'll close this one now so it doesn't annoy anyone anymore :) (I still think |
(This is related to work on Python 3 enums in #781)
class_API now requires calling.into_class()or doing a rvalue cast.value()and.export_values()now return rvalue*thisinstead of lvalueNote: this is technically a breaking change, but the consensus seems to be that this functionality was more of a side-effect (of deriving from
class_) rather than an intended feature.