-
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
Fail to compile if attempting to specifying MI bases via class_
ctor parameters
#742
Conversation
neat! That looks great (including your implementation) |
Looks like MSVC doesn't like your template forward declaration. |
As far as I have gathered, the main motivation for the alternative constructor-argument base specification is this: http://pybind11.readthedocs.io/en/latest/advanced/misc.html#partitioning-code-over-multiple-extension-modules If that's the case, the |
Ah, right, that's going to be a problem. |
If the compile-time type information is always required for multiple inheritance, perhaps it would be enough to require that MI must use the template parameter specification, limit the ctor arguments to single-inheritance-only and just report an error if > 1 |
Yeah, that sounds reasonable. |
Even better: it should be possible to make it a compile-time error. |
@dean0x7d: I'm not sure I follow -- why is compile-time information needed for MI? The documentation you referenced talks about cyclic dependencies, but that's not the case here, no? |
@wjakob - because MI requires a |
ah right.. I forgot about that. We need to create all the converters that let us jump through the hierarchy. |
So while we could support it for actual |
class_
ctor parametersclass_
ctor parameters
d9bd3fa
to
a07094f
Compare
none_of<is_pyobject<Extra>...>::value || // no base class arguments, or: | ||
( constexpr_sum(is_pyobject<Extra>::value...) == 1 && // Exactly one base | ||
constexpr_sum(is_base<options>::value...) == 0 && // no template option bases | ||
none_of<std::is_same<multiple_inheritance, Extra>...>::value), // no multiple_inheritance attr |
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.
It's pretty awesome that this can be a compile-time error!
One minor point, and feel free to ignore this since it's more about code style. The first none_of
and the first constexpr_sum
are repeating a bit of work. Consider assigning the sum to a variable to reuse the result. In general, assigning to variables would make the code more self-documenting, avoiding the need for any extra comments. E.g.:
constexpr auto compiletime_bases = constexpr_sum(is_pyobject<options>::value...);
constexpr auto runtime_bases = constexpr_sum(is_pyobject<Extra>::value...);
constexpr auto needs_multiple_inheritance = compiletime_bases + runtime_bases > 1 ||
any_of<std::is_same<multiple_inheritance, Extra>...>();
static_assert(!(needs_multiple_inheritance && runtime_bases > 0),
"Error: multiple inheritance bases must be specified via class_ template options");
(In addition to the variable names, the error message itself shows the overall intent.)
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.
There's one annoying issue (MSVC related, as usual) with doing it that way: MSVC considers all the constexpr variables unused if only used in the static_assert
, and so issues a warning which breaks the build, and so separate variables would need a (void) (compiletime_bases, runtime_bases, needs_mi);
to silence it, which is a bit ugly.
I thought it might also end up being potentially less work for the compiler this way: typically the number of base classes is 0, so short-circuiting avoids needing to compute everything but the first one.
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.
Given the MSVC warning bug, I think I'll merge as is.
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, better than adding workarounds.
We can't support this for classes from imported modules (which is the primary purpose of a ctor argument base class) because we *have* to have both parent and derived to properly extract a multiple-inheritance base class pointer from a derived class pointer. We could support this for actual `class_<Base, ...> instances, but since in that case the `Base` is already present in the code, it seems more consistent to simply always require MI to go via template options.
Rebased to make sure this works with MSVC 2017 (MSVC 2015u3 was very fragile around the static_assert: changing the |
Currently we only allow multiple inheritance viaclass_
template parameters; this extends the support toclass_
instances passed via the derivedclass_
constructor arguments as well.Edit: see discussion below. We can't support MI via parameters in the most useful case, so produce a compile time error instead.
Fixes #741