-
Notifications
You must be signed in to change notification settings - Fork 2.2k
std::variant of integral and bool populates wrong alternative #1625
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
Comments
Turns out the arithmetic conversion is even more permissive than this. It will consider any conversion to the arithmetic type as valid. For example, my code has a custom decimal class in c++ with a |
Also came across this issue - the variant population also doesn't appear to be completely deterministic. When calling a function with a |
I can confirm that this is still happening, but doesn't seem random. So, if someone is trying to do this, my workaround suggestion is this: Change the order of the std::variant and set bool, before ints. Example: Instead of
Do this:
|
Just bumped into this - is this going to be fixed any time soon? |
@m4ce: I don't currently have the time to track this down, so one of you will have to do so and create a PR with the fix & a testcase. Then it will be fixed. |
I don't think there's a lot we can do about this. The same overload resolution happens for e.g.: void bar(int v) {
std::cout << "int" << std::endl;
}
void bar(bool v) {
std::cout << "bool" << std::endl;
}
PYBIND11_MODULE(example, m)
{
m.def("bar", py::overload_cast<int>(&bar))
.def("bar", py::overload_cast<bool>(&bar));
} So The problem is the following Python behavior: >>> issubclass(bool, int)
True
>>> bool.__bases__
(<class 'int'>,)
>>> isinstance(True, int)
True I.e., a Python |
Note that C++ can get "confused" when it comes to variants that may be holding bools. The following paper was accepted for C++20, implemented in gcc 10, supposedly in clang 9 (but brief testing says that's a lie), and never in msvc. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r3.html However, C++ doesn't get confused about |
Interesting, but that's not the problem here, I believe, since it's reproduced with overloads as well. The main difference is that it's easier to reorder overloads than a (potentially internal and not changeable) C++ type. |
No further reaction. I'm closing this for now. If there's something that pybind11 can do about it, please reopen. |
@YannickJadoul said the problem is that in Python,
So if you have C++ functions In any case, I think the least you can do is describe the issue next to this table, which is currently oriented to passing values from C++ to Python, but the same conversion machinery applies also to passing values from Python to C++. Not only Python types don't map uniquely to C++ types, but pybind11's behaviour is not natural and even non-deterministic (as mentioned above) which is a real problem in my view. |
No they are not: https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
So pybind11 checks, one by one, if the value fits into a The underlying problem here really is that Python's |
Oh, I did not know that - thanks for the link. Is it mentioned somewhere in the documentation that the decision of the overload resolution depends on the value of the (Python) argument? If not, it would be nice to include it, e.g. in the Overload resolution order section. I think it is pretty important, especially for C++ programmers who are used to "type-only" conversions and not unlimited precision types. Btw. the real problem where I noticed this issue was with integer types nested in Also, what happens for floating-point types? Unless I'm doing something wrong, if we have a C++ function |
Well, it's definitely not specific to overload resolution. It's related to the fact that you can convert a Python 42 to e.g.
Yes, the first one. Easy to try out this one, if you want to be sure ;-)
What kind of conversions?
Yes, you're right. I believe the Python |
You are right about Please find a good place to describe the conversion of integers in the documentation, I think it is important to explain that for Python -> C++ it is more of a value conversion than a type conversion. If it does not fit, you can start a new section :) Thanks for your quick replies here. |
Yep, I see what you mean. But as you can see, it's a complex situation. Another option is changing the order of the members of that I don't immediately see when and how to add something to the cocs. If you get familiar with all aspects of pybind11 regarding |
Populating a variant containing an integral type and a
bool
from a Python bool may select the wrong alternative, depending on the ordering of alternatives.Consider the function
void foo(std::variant<int, bool> v)
. When called from Python with the expressionfoo(True)
, the valuev
in C++ will end up with theint
alternative populated with a value of1
. If the order of the alternatives are swapped such thatbool
occurs beforeint
, the boolean alternative will be populated, as expected.The reason this occurs is that the
type_caster
for integral types is defined for all types satisfyingis_arithmetic
, whichbool
satisfies, combined with the fact that loading abool
into an integer type is not considered a "conversion" in the context of theload
method, so it is selected on the first pass.I think this should be improved so that bool doesn't match the arithmetic type caster on the first pass.
The text was updated successfully, but these errors were encountered: