I'm not going to argue about the change for CONCRETE operators, I'm going to 
argue about the loss of power/flexibility for TEMPLATED operators, because it 
defeats the whole purpose of TEMPLATED functions/operators otherwise

I've attached the header file in question... it's mostly about outputting STL 
containers (like vectors, pairs, std::shared_ptr, the file name originates when 
I was just using it for vectors but I since expanded it to other STL 
containers, not sure that std::shared_ptr technically qualifies as a 
"container")

if there could be a sort of "carve out" for TEMPLATED operator<<  (actually all 
templated operators) so that declaration of *concretions* of the templated 
operator<< get inserted at the top of any file where they're used but the 
concretized definition gets inserted at the end of the first file where it's 
used, then my templated operator<< code SHOULD just work again... and this 
change would technically affect TEMPLATED operators rather than CONCRETE 
operators

here's an example 

I generally put toStream() methods on my classes (which are scoped by 
namespaces, with a pure virtual toStream() in the base class) and AT the end of 
the class' header file (unscoped/global scope) I'll inline a CONCRETE 
operator<<  for the class which just calls the class' toStream() function.

To explain where the std::shared_ptr comes into this
        My classes have heavy weight static ptrFactory methods (so they can 
throw exceptions, and the ptrFactory methods call do-nothing constructors that 
just copy stuff in) and produce a raw pointer        (so they can be swigged to 
java), with an inline static PtrFactory method wrapping that to produce a 
std::shared_ptr for (memory management in) C++ side use (this makes MOVING 
instances       around easy/cheap)

        In some other C++ file there will be a (usually SORTED) 
std::vector<std::shared_ptr<std::pair<SomeKey,std::shared_ptr<const 
SomeClass>>>>  
        This is basically a lighter weight map that I look up with 
std::lower_bound... one of the applications is a sort of statistical 
database/information-system where "tables" got replaced with smart      
histograms (and SomeClass="bins" of some histograms can be SomeClass=histograms 
for other variables, and the SomeKey could be a primitive, a pair or a vector, 
possibly a pair of vectors), 

        the outer std::shared_ptr is to make moving entries (e.g. in std::sort 
[with a custom comparator], or when inserting a new entry into an already 
sorted vector) cheap i.e. shallow copies rather than   deep copies (the inner 
shared_ptr is for indirection through polymorphism so the current histogram 
doesn't have to know/care about what type of concrete histogram it's bins are, 
and allowing the      lookup to happen on an entry with just key and the "bin" 
being a nullptr)

and somewhere (in a .cpp file rather than a .hpp file) I'll << the vector 
(a.k.a. table/histogram) (this is a usually a dump of a "table" or part of a 
"table" in an informative error message that gets thrown in an exception, or in 
the test suite, which has roughly the same number of lines as the real code not 
counting the SWIG generated wrappers)

If the declaration of the CONCRETE operator<< 
std::vector<std::pair<key,std::shared_ptr<const SomeClass>> gets inserted at 
the top of each "file" where it gets used and the concretized definition gets 
inserted at the "bottom" of the FIRST file where its used then all CONCRETIONS 
of the TEMPLATED operator<<'s SHOULD still just work  without undoing your fix 
for CONCRETE operators

Not sure how the compiler would know whether the current file was the FIRST 
file or not, but it seems like the same problem that had to be solved for class 
declarations/definitions when there are method definitions in the class 
declaration.

-----Original Message-----
From: Andrew Pinski <pins...@gmail.com> 
Sent: Thursday, July 11, 2024 6:16 PM
To: Dalbey, Keith <kdal...@sandia.gov>
Cc: gcc@gcc.gnu.org
Subject: [EXTERNAL] Re: g++12 broke my system of overloaded operator<<

[You don't often get email from pins...@gmail.com. Learn why this is important 
at https://aka.ms/LearnAboutSenderIdentification ]

On Thu, Jul 11, 2024 at 5:04 PM Dalbey, Keith via Gcc <gcc@gcc.gnu.org> wrote:
>
> So I'm on redhat 7 and just got devtoolsset-12 and code (a system of 
> overloaded<< operators) that was working with devtoolset-10 now break 
> (because of ordering)
>
> To not bury the lead..
>
> My code relies on the version 11 or older behavior (see below), and I don't 
> see how anyone could call the new behavior an improvement or correction 
> because it neuters/cancels out  the power/flexibility of the STL.   Yes one 
> could technically work around it by forward declaring templated operator<<  
> but that makes the system not extensible,  a common package/gitlab project 
> that handles this for the STL and then gets succeed into another library that 
> overloads the operator<< for concrete classes just doesn't work any more... 
> and that was my exact use case.

So your code depends on non-standard behavior that GCC accidentally got wrong 
until GCC 12.
I feel for you but ...

>
> Please reverse this change in future editions of gcc, it is absolutely awful.

This is not going to happen since your code depended on incorrect behavior. And 
code that depends on behavior defined by the standard would now break.

Thanks,
Andrew

>
> From this link
> https://gcc02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdeve
> lopers.redhat.com%2Farticles%2F2022%2F04%2F25%2Fnew-c-features-gcc-12%
> 23corrections_and_internal_improvements&data=05%7C02%7Ckdalbey%40sandi
> a.gov%7C2fe9158921c24b57de3e08dca207cc16%7C7ccb5a20a303498cb0c12900738
> 1b574%7C1%7C0%7C638563401601590446%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4
> wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&s
> data=XL8CsP%2F1%2F1iqVmn5qW2CLT1HJjaJPgq7F7B2Y%2F6kS58%3D&reserved=0
> Corrections and internal improvements
> The changes described in this section bring GCC more in line with recent 
> changes to the standard, and permit behavior that previously did not work 
> correctly.
> Dependent operator lookup changes
> GCC 12 corrected a problem where the compiler performed an unqualified lookup 
> for a dependent operator expression at template definition time instead of at 
> instantiation time. The fix matches the existing behavior for dependent call 
> expressions. Consider the following test case demonstrating this change:
> #include <iostream>
>
> namespace N {
>   struct A { };
> }
>
> void operator+(N::A, double) {
>   std::cout << "#1 ";
> }
>
> template<class T>
> void f(T t) {
>   operator+(t, 0);
>   t + 0;
> }
>
> // Since it's not visible from the template definition, this 
> later-declared // operator overload should not be considered when 
> instantiating f<N::A>(N::A), // for either the call or operator expression.
> void operator+(N::A, int) {
>   std::cout << "#2 ";
> }
>
> int main() {
>   N::A a;
>   f(a);
>   std::cout << std::endl;
> }
> Copy snippet
> This program will print #1 #2 when compiled with versions 11 or older of GCC, 
> but GCC 12 correctly prints #1 #1. That's because previously only the call 
> expression resolved to the #1 overload, but with GCC 12 the operator 
> expression does too.

Attachment: vectorConvenience.hpp
Description: vectorConvenience.hpp

Reply via email to