Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c++ Subject: Re: C++20 concepts rocks Date: Wed, 09 Feb 2022 21:25:37 -0800 Organization: A noiseless patient Spider Lines: 142 Message-ID: <86czjvi97y.fsf@linuxsc.com> References: <87k0easj5d.fsf@bsb.me.uk> <865yptlpgf.fsf@linuxsc.com> <87mtj4qd0h.fsf@bsb.me.uk> <86fsovkdjw.fsf@linuxsc.com> <877da7r7ap.fsf@bsb.me.uk> <86bkzjjs3c.fsf@linuxsc.com> <87k0e6q4j8.fsf@bsb.me.uk> <8635kukb17.fsf@linuxsc.com> <878rumptie.fsf@bsb.me.uk> <86leymiga7.fsf@linuxsc.com> <877da3n2au.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="adc012712597ca793e8fc11fa93282ed"; logging-data="3456"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19dy1dauEeNawSJKHcd4StGKkAb458caYM=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:Z/cxDcP2tZ47HqBM8Iz/nz8atRc= sha1:17x0GMnU1QA/AyH1ldt9AktaUCE= Xref: csiph.com comp.lang.c++:82979 Ben Bacarisse writes: > Tim Rentsch writes: > >> Ben Bacarisse writes: >> >>> Tim Rentsch writes: >>> >>>> Ben Bacarisse writes: >>>> >>>>> Tim Rentsch writes: >>>>> >>>>>> Ben Bacarisse writes: >>>> >>>> [.. considering the idiom (&x)[1], where x is an array ..] [...] >>>> Sorry, yes. In some cases in C, and in C++, using a cast may be >>>> the only option: >>>> >>>> char result[20]; >>>> char *ep = (char*)( &result + 1 ); >>> >>> Thinking about this a bit more I not 100% convinced; or perhaps >>> I am just a little uneasy about how easy it would be to get this >>> wrong. >>> >>> Switching to int (so that any special rules about accessing an >>> object's byte representation using a pointer to char don't come >>> into play) this >>> >>> int result[20]; >>> int *ip = (int *)(&result + 1); >>> >>> allows accesses like ip[-1], so (unless I'm missing some other >>> rules) this >>> >>> int result2[2][20]; >>> int *ip = (int *)(&result2[0] + 1); >>> >>> allows access to result2[0] via negative indexes, but not to >>> result2[1] using positive ones, despite the fact that the >>> pointer being converted is a pointer to the second subarray of >>> 'result2'. Is that how you see things? >> >> If you think you're going to confuse [me] with these questions, >> well it is quite possible that you will. :) >> >> Having said that, I press on. >> >> Certainly the expression 'result2' is able to access any object >> within the confines of the two-dimensional array result2. >> >> Similarly the expression 'result2 + 0' is able to access any >> object with in the confines of the two-dimensional array result2, >> because 'result2 + 0' is exactly the same pointer as 'result2'. >> >> The expression '&result2[0]' is, by definition, the same as the >> expression '& * (result2 + 0)'. (Sidebar: in C that is always >> true, whereas in C++ things may be different because of operator >> overloading or something like that. I am assuming that these >> possibilities don't come into play here, and '&result2[0]' acts >> the same way in C++ as it does in C. (End sidebar.)) >> >> In C there is a rule that &*(E) is the same as (E) as long as the >> constraints for the two operators are met. So in C '&result2[0]' >> gives the same results as just 'result2', which is to say it is able >> to access any object within the confines of the two-dimensional >> array result2. >> >> [...] >> >> Returning to your question, the expression '&result2[0]+1' is, in >> C, the same as 'result2+1', which allows access to all of result2. > > Sorry for the delay. Life got in the way. Your arguments are > compelling, but I am left unsure if, for any given pointer > expression, I could work out, using the C++ standard text, the n > and i that would allow me to know what values of j are permitted. > (I'm referring to the 0 <= i+j <= n and the 0 <= i-j <= n in 7.6.6 > p4.2. Rather than thinking about pointer values, it might help to start with objects. If we have this declaration int a[2][3]; what are the objects? They are a ( == (&a)[0] ) a[0] a[1] a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] along with the "hypothetical" objects (&a)[1] (&a)[1][0] (&a)[1][0][0] a[2] a[2][0] a[0][3] a[1][3] Keep in mind that these forms are not meant to be read as expressions but just as a way of naming objects. If we put an & in front of any of the above, now considered as an expression, we get a pointer value that is allowed to be adjusted to (ie, using pointer arithmetic) any other form that is the same except for the last dimension. So if for example we have &a[0][1] we can use pointer arithmetic to obtain a pointer to any of a[0][0] a[0][1] a[0][2] a[0][3] (with the last item naming a "hypothetical" object), but not any of the other objects. Of course if we have or can get a pointer to a containing object we can obtain a pointer to any of its contained objects. To say that another way, if we have a pointer to an array, we can obtain a pointer to any of the elements in the array (and that holds recursively). Casting a pointer to a different type doesn't change what objects it can access. At least, this rule holds in C, and I believe it also holds in C++. Disclaimer: it is possible C++ has some sort of magic library functions that do allow something along these lines, but if it does I don't know about it. Forgive me if any of the above seems obvious. I am unsure about what kind of situations you might not be sure of. Does this explanation help with your uncertainties?