When defining a friend function in a template class it does not get correctly defined if the class instantiation comes after the function has been already called. Note: this happens even if you pre-declare the function in its correct context before the same function is called. The following is a code sample that reproduces the bug. Note that this has been already discussed and concluded that this is valid c++ standard-compliant code (precisely here: http://groups.google.com/group/comp.lang.c++/browse_frm/thread/493afd501c807ffe#). -- code -- void Function(); int main(int argc, char* argv[]) { Function(); // This does not work } template <typename T> class Test { public: friend void Function() { printf("Function()"); getchar(); } }; template class Test<int>; -- end code --
Any news?
Confirmed, not a regression. If you swap around main and the template, the link works correctly.
Sorry for the late reply! I thought I'd receive an e-mail when one of my reports gets updated, silly me. Yes I know it works if you switch the order, but that's exactly the point of the code, to have them in that specific order and there's no reason why the code as it is shouldn't work being it standard c++ right?
Confirmed indeed, with this (linker) error message: g/x> c++ x.cc /tmp/ccjPvb3J.o: In function `main': x.cc:(.text+0x12): undefined reference to `Function()' collect2: ld returned 1 exit status This already fails with gcc2.95. W.
Any update about this?
Did anyone try this against 4.5? Considering that at this stage only bugfixes are accepted in the codebase for the next release I'd really like to see a possible fix to this in. I tried to compile GCC 4.5 on my machine without much success.
Doesn't link with 4.5.0. And doesn't link with ICC and SunStudio either, thus, I'm rather skeptical it should. I also skimmed quickly through the discussion on comp.lang.c++ and didn't notice any neat statement... maybe should look better.
See http://www.open-std.org/jtc1/sc22/wg21/prot/14882fdis/cwg_defects.html#329 I believe a "use" of the function must come after the definition for it to be instantiated, indeed if I add this after the explicit instantiation it links OK: void(*pf)() = &Function;
I know if you move the function it links (btw your link asks me for an HTTP login), but if you follow the discussion in the newsgroup it was concluded that this (the above) is actually perfectly valid standard C++ code, and anyway I think at least the error the linker gives could be more descriptive. Also the fact that other compilers fail with this code it's just because it's fairly rarely used code. For instance, Open Watcom compiled and linked the code perfectly fine without issues (and the executable was working).
Try this one: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#329 Anyway, if you could point us to the specific sentence in the thread saying that it's legal, it would be useful. And, well, frankly I would not trust Watcom more than Intel and Sun (and GCC) together ;) But let's CC Jason, maybe he wants to give his opinion...
This is possibly the part in which gets confirmed that the code is standard compliant, although it reports the exact same paragraph you linked (the old version): http://groups.google.com/group/comp.lang.c++/tree/browse_frm/thread/493afd501c807ffe/68c709135884bac7?rnum=11&_done=%2Fgroup%2Fcomp.lang.c%2B%2B%2Fbrowse_frm%2Fthread%2F493afd501c807ffe%3F#doc_38f8441247122dcd I guess that page is some kind of errata corrige? Anyway maybe I'm missing something but I see that as a conflict. If I recall correctly it is stated that the context of a injected friend function must not be ambiguous, thus meaning you have to declare it first in the correct namespace. The idea of declaration is that you inform the compiler that the function exists somewhere so that you can use it without having it defined yet. If friend function injection is just like defining the function in the parent namespace of the class and if a template exists as a type (at linking level) only when you create an instance of that type, it means the moment you instantiate the template, then the type is defined and consequently the friend function is injected, thus matching with the declaration done before, thus matching with the call that used that declaration. As I pointed in that newsgroup thread, it works fine with normal classes, and theoretically a template is just a class in the second you create an instance of it. I don't precisely understand why there should be an exception for templates. I understand not defining the function if you don't create any instance of the template, but otherwise it's a bit unclear to me why there should be this exception.
Created attachment 19387 [details] patch Here's a fix. I'm going to hold off on applying it for now since it isn't a regression.
Cool. Should the testcase use dg-do link?
Ah, good point. I've updated the patch accordingly in my local pre-4.6 git branch.
Hey thank you! I'd like to test the patch if I only I'd be able to compile 4.5 successfully. You have any idea on when could this patch make it to a final release?
As Jason confirmed, this is not a regression, thus, post 4.5.0.
Ok I managed to compile GCC 4.5, applied the patch and compiled the test code above and everything works fine. Thanks again! And yes, I imagined it would have been post 4.5 but I meant 'when' from a time frame point of view, that's why I said "you have any idea" as I know it's hard to predict a specific time for release.
If I were you, I would not use this kind of C++ at all, for the time being. As we discussed already, it's *very* weakly supported and your software would not be portable.
Yeah I know, but consider that I used this code only in a specific circumstance and does not constitute a core part of my application (or a foundation of some higher level mechanism). And I know it's a lot like an exploit but it does allow me to add a tiny yet very slick feature to my code. Also I checked and they fixed this in visual c++ 2010 as well (after my report), so having the two major compilers supporting this code is good enough for me.
Then wait, good luck
Subject: Bug 38392 Author: jason Date: Wed Apr 7 15:54:42 2010 New Revision: 158073 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=158073 Log: PR c++/38392 * pt.c (tsubst_friend_function): Instatiate a friend that has already been used. Added: trunk/gcc/testsuite/g++.dg/template/friend51.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/pt.c trunk/gcc/testsuite/ChangeLog
Fixed for 4.6.