Uh oh!
There was an error while loading. Please reload this page.
Remove <iterator> header from span.hpp - #179
Conversation
comment out iterator header include to see if it breaks something
pdimov
commented
Nov 25, 2024
In this case we can probably get by without that include because Incidentally, |
Ah, my mistake, should have checked this better, I noticed typedefs, but I presumed they are all just raw pointers/references. As for
(libc++ uses some algo headers, but not the full |
Lastique
commented
Nov 25, 2024
FWIW, my principle is that whatever is directly used in the header must be included in that header. That is, I try to never rely on transitive includes. If including As for |
pdimov
commented
Nov 26, 2024
I'm not sure why we need the special case for |
Lastique
commented
Nov 26, 2024
I suspect that's because there there are slight differences between constructors from BTW, I think, the constructor from ranges when the span extent is not dynamic is poorly defined. Specifically, if the span extent is larger than the range size, the constructor will happily succeed and produce a span that is larger than the original range. I would rather such code just not compile at all. |
pdimov
commented
Nov 26, 2024
Ah, right, |
libbooze
commented
Nov 26, 2024
If you are referring to this scenario |
pdimov
commented
Nov 26, 2024
Interesting. This doesn't make much sense to me, given the recent push towards increased safety. |
Yes, and I consider this a bug in the specification. And we should probably do better in Boost. I.e. either not offer this constructor (which is easy) or restrict it so that it is only enabled when it's safe (which may be more difficult). |
pdimov
commented
Nov 26, 2024
Ah, the above only compiles for |
Lastique
commented
Nov 26, 2024
Yes, but it doesn't make the constructor from a range safe. |
pdimov
commented
Nov 26, 2024
How could the constructor from a range be made safe? The range size isn't known until runtime. |
Lastique
commented
Nov 26, 2024
One idea is https://eel.is/c++draft/span.cons#15.1 should be made not precondition but a constraint. Which would mean Another idea is to perform a runtime size check and throw if the check fails. In any case, I think the support for static span size is a design misfeature that adds more problems than benefit. This is one of the reasons why I still prefer |
pdimov
commented
Nov 26, 2024
As for runtime check, the standard makes this a precondition, which means that it could be checked. This would at least mean a BOOST_ASSERT in our case, but it doesn't look like we have it. https://godbolt.org/z/xqhMWEYox |
Lastique
commented
Nov 26, 2024
Ok, let's paraphrase
Sorry, this reasoning doesn't work. We have at least one implementation that doesn't check, which means the code cannot rely on the check and therefore is not safe. Historically, preconditions were never enforced by implementations other than in special modes, like debug or even stronger "safe" modes that were not intended for production. IMO, the constructor in question is way too error-prone to rely on the user satisfying the precondition. |
Lastique
commented
Nov 26, 2024
BTW, the case of |
libbooze
commented
Nov 26, 2024
Yes, my mistake for not being explicit. I used I was curious if we could detect that size is fixed since it is available at compile time, but it turns out that since they made vector constexpr this will not work, e.g. this program compiles It may be possible to make a "good" concept for detecting fixed size ranges so that
Yes, I picked |
glenfe
commented
Nov 26, 2024
A detail reverse_iterator in span is also an option. It would be unfortunate if the appreciation in libraries assuming C++11 or higher now is offset by them reimplementing even parts of C++03 for these reasons. |
Come to think of it, we might still need to include |
pdimov
commented
Nov 26, 2024
Yes, I managed to discover this twice (because I forgot). I occasionally need such a detection, but I haven't been able to find a way to do this reliably, so I settled on an explicit trait: https://github.com/pdimov/hash2/blob/develop/include/boost/hash2/has_constant_size.hpp |
pdimov
commented
Nov 26, 2024
Looks like this is going to change: cplusplus/papers#2125
So you're for the outright removal of this constructor? I myself have never been particularly fond of statically sized spans and the associated complexity they brought, but on the other hand, not matching the standard exactly almost always creates complaints. In either case, we are missing at least one BOOST_ASSERT here, aren't we, folks. |
libbooze
commented
Nov 26, 2024
Yes, shame, would be nice if C++ decades ago decided to use member presence to detect iterator category, e.g. Also would be nice for boost if
In any case I think feasibility of getting rid of Let me elaborate:
In this case Sorry for the long comment that turned into policy suggestion, but I believe it would be nice if boost.core picked an approach(either 2. or 3.) or better one I did not consider. While this analysis may appear to support merging the pull request, actually I am fine with it being rejected and accepting that |
pdimov
commented
Nov 26, 2024
Any "let's make our headers more granular" standard proposal now gets answered with "modules fix everything". Let's hope modules do indeed fix everything, because standard headers are getting heavier and heavier with each subsequent standard. On our side, I always include the standard header the standard says needs to be included and seethe. There are some tricks you can legitimately play, such as including |
Lastique
commented
Nov 26, 2024
I think:
All of the above is regarding the fixed-size span. The dynamically sized span does not need any size checks, obviously. |
libbooze
commented
Nov 26, 2024
As far as I know real life results of Office experiment are a bit better(around 15%) than PGO. Not great, not terrible, but definately not just include everything you want and it is still 20x faster than headers.
To play defense attorney for static extent re matching standard: re asserts and runtime checks: |
If I understood discussion above correctly issue is that we can not detect types with compile time known size using SFINAE/concepts. We must explicitly list them or they must explicitly proclaim themselves to be of constant size. That may be one of reasons(beside explicit) why edit: with concepts it might work, but not sure how reliable it would be since concepts are syntax, not semantic checks. |
Lastique
commented
Nov 26, 2024
My hope is to live long enough to see modules ubiquitous. Because it doesn't seem like they will be of much help while half of the code base uses includes and the other half modules, yet this is what we can expect to see in the coming decades.
My approach in public headers is:
|
libbooze
commented
Nov 26, 2024
Maybe I should have made it more explicit that my suggestion of option 3. only applies to Boost.Core. As you know documentation says:
So even if |
The main rationale is separation of complexity and use cases. If you look at The interface complexity of span also leaks onto the users, as if you want to have And also I would say that fixed-sized spans are more rarely used and the use cases are different from the dynamic sized ones. Similarly to how they are different for |
Lastique
commented
Nov 26, 2024
Ah, right, I forgot about that. |
Not experienced enough to answer about generic algorithm, I presume I would just use |
libbooze
commented
Nov 27, 2024
Hi @pdimov@Lastique First part is investigation of what causes constexpr evaluation failures(beside obvious stuff like accessing wrong memory or calling non constexpr function). Answer is that it depends on if we use libc++ or libstdc++ since libstdc++ has checks(and they are enabled in constexpr mode always). I think this makes sense and this old comment seems to suggest it is not an accident. Second step we need to do is to do a bit of poking of type from which span is constructed ( Third thing is to specify what we know about
If answers are no, no we learn nothing, as maybe it is just a container that is not constexpr friendly. But what is interesting is the following: if Full example is here. As mentioned downsides are that we are relying on check in But still does not seem like a terrible idea to do checks like this even if only for libstdc++. But to be honest seems like a lot of machinery to add to Boost.Core, so I am happy to hear if you have some suggestions to shrink it down. I have not measured compile times impact, godbolt link is super slow due to |
pdimov
commented
Nov 27, 2024
I'm not sure this will buy us much, because it's very uncommon for a fixed size The only example that comes to mind is |
Lastique
commented
Nov 27, 2024
I think this is too much of a stretch. Template parameters can have any meaning, we can't be guessing. I don't think this is something we can use as a criteria for detecting fixed-size ranges. Looks like the best we can do right now is to check static sizes for the ranges we know ( |
libbooze
commented
Nov 27, 2024
Well it also checks this does not compile
Not always true if I read current code correctly. True for Beside other span and array implementations I think this might also catch some wrong usages of Don't get me wrong, I do not want In any case if you think this is an overkill I kind of agree, I just wish we could do proper checks without such a complex mechanism needed. At least I learned some new C++ tricks in past few days. :) |
pdimov
commented
Nov 27, 2024
We can forward-declare anything from Boost (e.g. boost::array), so we don't need to include any headers; only std:: is a problem. I think that I also tried |
Can't we just add a deleted overload that is enabled when |
pdimov
commented
Nov 27, 2024
And maybe another when |
libbooze
commented
Nov 27, 2024
Yes, but that will not work for all cases. As mentioned above that works for |
I would say not
Great suggestion, did not think of that since most of time it is some huge number(e.g. for |
Lastique
commented
Nov 27, 2024
This will be problematic if I suppose, for types that don't pass this check, for one reason or another, we would just do a runtime size check. So, the overload can be considered as just an optimization to eliminate the runtime overhead. |
True in my experiments, that is first thing I tried, then I felt silly because obviously you can not call methods on "invented" instance, you need to really construct the object. |
pdimov
commented
Nov 27, 2024
For types that don't pass the check, the overload will be dropped, and the "normal" one will be selected.
|
pdimov
commented
Nov 27, 2024
Something like this: https://godbolt.org/z/YGnj8GW1E |
Not sure that will help, as paper mentions static member function. Sure
This looks very nice! It does not solve the problem of In my example I just say if result of |
pdimov
commented
Nov 27, 2024
No, the function doesn't have to be static. See https://godbolt.org/z/r7or63G8n. This only works with GCC 14. |
pdimov
commented
Nov 27, 2024
It does, yes. I suppose we need the |
libbooze
commented
Nov 27, 2024
If you want I can make the pull request. It will take a lot more time than if you did it, but I would be quite happy to do it. Will make sure to add tests, not sure how to test compile failures, probably there are some examples I can copy from. |
pdimov
commented
Nov 27, 2024
@glenfe is the maintainer of |
On a not entirely unrelated note, the logic in Boost.Move that tries to play games to get |
igaztanaga
commented
Nov 27, 2024
Looks like now lives in https://github.com/llvm/llvm-project/commits/main/libcxx/include/__utility/swap.h |
igaztanaga
commented
Nov 27, 2024
See boostorg/move@b7a04d3 for a fix. Let me know if we should merge this into master. |
Lastique
commented
Nov 27, 2024
I think it's worth merging, provided that the tests pass. |
igaztanaga
commented
Nov 27, 2024
Regression tests ok: https://github.com/boostorg/move/actions/runs/12057774672/job/33623124544, asking for permission to merge to release managers. |
libbooze
commented
Dec 2, 2024
Hi @pdimov I am not really familiar with C++11 TMP, so I wonder if you know a better way to
|
libbooze
commented
Dec 3, 2024
@glenfe since you are maintainer of span: |
edit: this description missed use of
std::reverse_iterator, please see comments bellowDue to reasons unrelated to this pull I was looking into how slow/fast to compile
span.hppand<span>are.I have noticed that
<span>compiles faster and that preprocessed output (-Ecompiler flag) has around 20k lines less.It turns our that is mostly due to include of
<iterator>header. This measurement is limited to just my setup(libstdc++) and results may be different for some other std implementation.As far as I know
<iterator>is not needed for span functionality, and tests seem to pass. Note that I am not a boost dev so IDK how to properly test all users of this header, but for example I have tested beast beside running tests in core and all seems fine.This is not super important change since huge percentage of users will eventually use some part of STL that will drag in
<iterator>header, but I still believe we should fix this(if nothing is broken by this change) for 2 reasons:<iterator>