-
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
Convenience constructor templates for buffer_info #860
Conversation
0fe6005
to
b693b01
Compare
That's a nice reduction of arguments. Looks good to me. |
Somehow the builds are failing on gcc 4.8, though. gcc 6 and clang do work. And on my own system (gcc 5.4), I had to use brace-initialization. For some reason, it seems that the compiler first moves the arguments to the other constructor, and only then gets the |
…ize, format string, and number of dimensions from the pointer type and the shape container
b693b01
to
09b1f95
Compare
I think the frequent false positives on AppVeyor have desensitized me to seeing red in CI status. Totally missed the gcc 4.8 error. |
It's an argument evaluation order issue. |
I'd agree, but there's two things why I'm not completely convinced:
|
Ah, but, stack overflow knows about a gcc bug: https://stackoverflow.com/questions/14060264/order-of-evaluation-of-elements-in-list-initialization Edit: another interesting StackOverflow thread: https://stackoverflow.com/questions/24814696/move-semantics-and-function-order-evaluation |
Regarding point 1, each argument is fully evaluated before moving on to the next one, so the rvalue-reference cast and move-constructor call happen back-to-back. MSVC has the same bug as gcc 4.8 regarding brace evaluation order. AFAIK this only affects calling constructors with braces, but not Unless someone has a better solution, I think making a copy of |
I ran into exactly the same issue in |
Let's see... *fingers crossed* Edit: woohoo, GCC 4.8 already seems to have succeeded. Should I also implement this solution for |
include/pybind11/buffer_info.h
Outdated
@@ -79,6 +72,18 @@ struct buffer_info { | |||
} | |||
|
|||
private: | |||
struct private_ctr_tag { explicit private_ctr_tag() = default; }; |
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.
Is there any pointer in declaring the default constructor here? (I.e. instead of just struct private_ctr_tag {};
?)
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.
I think I saw that somewhere, and reckoned explicit
would be appropriate for the constructor. But there's actually no point, since it's all private, anyway.
Actually, I don't think it's needed anymore; I forget exactly where it happened, but it looks like the current |
Is there a reason for these two interfaces ( |
Oh, also, on the topic of std::fill(strides.begin(), strides.end(), itemsize);
for (size_t i = 0; i < ndim - 1; i++)
for (size_t j = 0; j < ndim - 1 - i; j++)
strides[j] *= shape[ndim - 1 - i]; could be simplified to the more efficient strides[ndim - 1] = itemsize;
for (size_t i = 1; i < ndim; ++i)
strides[ndim - 1 - i] = strides[ndim - i] * shape[ndim - i]; If we leave |
Already pending in #762. |
…uctor taking rvalue reference, solving the evaluation order move problem
8cd91b1
to
2f2b803
Compare
I need the same trick in #762, so how about moving the |
Actually, never mind that. I'll move it as part of #762; you can leave this PR as-is. |
include/pybind11/buffer_info.h
Outdated
for (size_t i = 0; i < (size_t) ndim; ++i) | ||
size *= shape[i]; | ||
} | ||
|
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.
Perhaps this could be redesigned a bit to only use this private constructor when you need the delegation, i.e. just in the one constructor at line 34 that wants to both move and call ->size
. It makes the code a little easier to follow (one fewer delegation for most constructors), and invokes fewer moves. It's also essentially a workaround for MSVC and old gcc, rather than a particularly desirable design.
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.
This is what you mean?
This costs one extra move when you use the buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
overload (as the private constuctor forwards it to the original overload and that one takes the containers by value before moving it into the data members, while before, the private constructor moved it immediately into the private members).
Then again, even if the optimizer doesn't figure that out, that extra move won't be thát costly, of course.
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.
Oh, right, it's not actually fewer delegations. Still, I like the idea of keeping the workaround as out-of-the-way as possible rather than pushing everything through it.
Merged, thanks @YannickJadoul! |
In order to reduce the amount of error-prone constructor arguments,
buffer_info
would now have a constructor template similar toarray
to automatically get the item size, default format string and number of dimensions.