Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Template friend function injection

9 views
Skip to first unread message

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 10:30:43 AM7/11/08
to
Hi, I have a question about injecting friend functions within template
classes. My question is specific to gcc (version 3.4.5) used in
combination with mingw because this code (or at least code that gets
the same result) works as expected in visualc++. I know that this is
probably not the right behavior for a compiler but it's the kind of
behavior I'm searching for so I was hoping there was a way to do the
same thing in gcc.
As you know when you define a class (with no template) and within the
class you define a friend function, the function is injected in the
scope directly outside of the class itself.

--- code ---

void Function();

int main(int argc, char* argv[])
{
Function(); // This works
}

class Test
{
public:
friend void Function() { printf("Function()"); getchar(); }
};

-- end code --


Now I would like to mimic the same behavior with template classes, but
this code doesn't work:

-- 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 --

Specifically I receive an error at link time about Function() not
being defined, which I guess is due to the compiler not considering
the definition of Function to be a non-template function and instead
assuming it to be a template function just because it's defined inside
of a template class.
Now, the funny thing is that if you move the main() BELOW the explicit
instantiation of the template class Test, this code actually compile
and works, that's why I consider it to be a "bug" because
theoretically if the definition of Function() is a template function
(thus not a normal function) it should never be used for the call
inside of the main() function, whether the main() function is below
the instantiation or not. Am I right?
Anyway I'm searching for a way to make the definition of Function()
available for the main() function even if the main() function is above
the template instantiation. Is there a way to accomplish this for gcc?
Like some command-line flag or something? I'd really appreciate that.
Thanks.

Marcel Müller

unread,
Jul 11, 2008, 11:37:26 AM7/11/08
to
H9XLrv5o...@spambox.us wrote:
> -- code --
>
> void Function();
>
> int main(int argc, char* argv[])
> {
> Function(); // This does not work
> }

Obviously you are calling an external version of Function here.


> template <typename T>
> class Test
> {
> public:
> friend void Function() { printf("Function()"); getchar(); }

Now you define Function inline. this is an error.

> };
>
> template class Test<int>;
>
> -- end code --


> Specifically I receive an error at link time about Function() not
> being defined, which I guess is due to the compiler not considering
> the definition of Function to be a non-template function and instead
> assuming it to be a template function just because it's defined inside
> of a template class.

No. It is because Function is declared as extern so far which is
obviously wrong.

> Now, the funny thing is that if you move the main() BELOW the explicit
> instantiation of the template class Test, this code actually compile
> and works, that's why I consider it to be a "bug" because
> theoretically if the definition of Function() is a template function
> (thus not a normal function) it should never be used for the call
> inside of the main() function, whether the main() function is below
> the instantiation or not. Am I right?

No. The second approach is valid code. You call Function after it is
defined inline.

> Anyway I'm searching for a way to make the definition of Function()
> available for the main() function even if the main() function is above
> the template instantiation. Is there a way to accomplish this for gcc?

Inline functions must be defined before their use. There is no way
around this.
I would prefer to define Function outside the body of Test. Like that:


void Function();

int main(int argc, char* argv[])
{
Function(); // This does not work
}

template <typename T>
class Test
{
public:

friend void Function();
};

template class Test<int>;

void Function()
{ printf("Function()"); getchar(); }


Marcel

Victor Bazarov

unread,
Jul 11, 2008, 11:44:24 AM7/11/08
to
Marcel Müller wrote:
> [..]

> Inline functions must be defined before their use. There is no way
> around this.
> [..]

So, you're saying that the following should not compile/link?

int foo();
int main()
{
return foo();
}
inline int foo() { return 0; } // note the 'inline'

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Alf P. Steinbach

unread,
Jul 11, 2008, 11:56:59 AM7/11/08
to
* Victor Bazarov:

> Marcel Müller wrote:
>> [..]
>> Inline functions must be defined before their use. There is no way
>> around this.
>> [..]
>
> So, you're saying that the following should not compile/link?
>
> int foo();
> int main()
> {
> return foo();
> }
> inline int foo() { return 0; } // note the 'inline'

Darned if I know. However, Marcel is wrong about must be defined before use
(there's even a note to the contrary in the standard). What I can't find
anywhere are the rules governing redeclaration of a function with different
'inline' characteristic. I know that in the FAQ it's simply assumed that OK,
this is how it works, you're free to /add/ 'inline'. But I can't find that in
the standard.

Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 12:07:39 PM7/11/08
to
On Jul 11, 5:37 pm, Marcel Müller <news.5.ma...@spamgourmet.org>
wrote:

>
> Obviously you are calling an external version of Function here.
>
> > template <typename T>
> > class Test
> > {
> > public:
> >    friend void Function() { printf("Function()"); getchar(); }
>
> Now you define Function inline. this is an error.
>

Sorry, but why the function is defined as inline if I define it inside
of a template and it is not if I define it inside of a normal class?


>
> No. It is because Function is declared as extern so far which is
> obviously wrong.
>

Well, then this page is wrong (or at least confusing):
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.16
It says:
"After the compiler sees that magic stuff, it will be better informed
about the friend functions. In particular, it will realize that the
friend lines are referring to functions that are themselves templates.
That eliminates the confusion.

Another approach is to define the friend function within the class
body at the same moment you declare it to be a friend."

>
> No. The second approach is valid code. You call Function after it is
> defined inline.
>

Then it means that the code in the first section (when the function
Function() is defined within the non-template class) should be wrong
too, and thus signaled by the compiler/linker, isn't it?

>
> Inline functions must be defined before their use. There is no way
> around this.
> I would prefer to define Function outside the body of Test. Like that:
>
> void Function();
>
> int main(int argc, char* argv[])
> {
>         Function(); // This does not work
>
> }
>
> template <typename T>
> class Test
> {
> public:
>         friend void Function();
>
> };
>
> template class Test<int>;
>
> void Function()
> { printf("Function()"); getchar(); }
>
> Marcel

Unluckily I can't do that because the whole purpose of this approach
was to do something with T inside of the Function() function. Using
templates so that the function is defined only at the very final
moment when someone instantiate the Test class with some template
argument.

gpderetta

unread,
Jul 11, 2008, 12:09:28 PM7/11/08
to
On Jul 11, 4:30 pm, H9XLrv5oXVNvH...@spambox.us wrote:
<snip>

> As you know when you define a class (with no template) and within the
> class you define a friend function, the function is injected in the
> scope directly outside of the class itself.
>
AFAIK friend injection is prestandard behavior. The standard requires
friend functions defined inside a class *not* to
be injected in the namespace the class is defined in. The only way to
call such a function is via argument dependent lookup (thus a nullary
inline friend function cannot be called at all). Older GCCs accepted
such code by default, but this extension has been removed from recent
GCCs. There might be an option to re-enable this feature , but it is
better to fix the code.

HTH,

--
gpd

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 12:16:02 PM7/11/08
to

Well the problem is that I was hoping in this trick to use a
particular technique.
Also in the GCC documentation there's written that the thing that's
not allowed is to declare AND define a friend function within a class,
thus creating a new symbol and injecting the function itself.
Instead you must first declare the function in the scope you're
injecting it in and then you can "inject" just the body of that
function and that's exactly what I'm doing. I could be wrong though,
that's why I'm asking here if there's any way to accomplish this.

Victor Bazarov

unread,
Jul 11, 2008, 12:37:11 PM7/11/08
to
gpderetta wrote:
> On Jul 11, 4:30 pm, H9XLrv5oXVNvH...@spambox.us wrote:
> <snip>
>> As you know when you define a class (with no template) and within the
>> class you define a friend function, the function is injected in the
>> scope directly outside of the class itself.
>>
> AFAIK friend injection is prestandard behavior. The standard requires
> friend functions defined inside a class *not* to
> be injected in the namespace the class is defined in.

The difference with the OP's case, however, is that the function is
already in the namespace scope by virtue of having been declared there.

> The only way to
> call such a function is via argument dependent lookup (thus a nullary
> inline friend function cannot be called at all). Older GCCs accepted
> such code by default, but this extension has been removed from recent
> GCCs. There might be an option to re-enable this feature , but it is
> better to fix the code.
>
> HTH,
>
> --
> gpd

V

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 12:42:57 PM7/11/08
to

So does it mean that my syntax of function injection is standard-
compliant? And do you know of a way to accomplish the same thing
within the template class?

Marcel Müller

unread,
Jul 11, 2008, 12:53:37 PM7/11/08
to
H9XLrv5o...@spambox.us wrote:
> On Jul 11, 5:37 pm, Marcel Müller <news.5.ma...@spamgourmet.org>
> wrote:
>> Obviously you are calling an external version of Function here.
>>
>>> template <typename T>
>>> class Test
>>> {
>>> public:
>>> friend void Function() { printf("Function()"); getchar(); }
>> Now you define Function inline. this is an error.
>>
>
> Sorry, but why the function is defined as inline if I define it inside
> of a template and it is not if I define it inside of a normal class?

It is always inline. However in case of a normal class the compiler does
not assume, that the function is not used by another object module in a
way that does not allow inline - e.g. taking the address. Therefore the
compiler always generates the code for the non-inline function and
associates it with a weak symbol. If it is not used or if there are
multiple implementations on linkage, the linker discards superfluous
instances.
In case of templates the compiler behaves different. Since templates
have always to be defined before usage. The compiler generates the
non-inline code only on demand in the current object module. The
explicit template instantiation is not sufficient for that.


>> No. The second approach is valid code. You call Function after it is
>> defined inline.
>>
>
> Then it means that the code in the first section (when the function
> Function() is defined within the non-template class) should be wrong
> too, and thus signaled by the compiler/linker, isn't it?

No, that's fine. The compile only silently calls the non-inline version
of Function because it does not yet have an implementation.

However, Alf P.Steinbach is right. The standard does not make such
restrictions. It mainly defines that it is not an error to have
redundant symbols in different object modules in this case. It always up
to the compiler to inline the code or not.
But from the implementation point of view, it is obvious that you cannot
inline a function before their definition. That would require a two-pass
compilation.


>> I would prefer to define Function outside the body of Test. Like that:
>

> Unluckily I can't do that because the whole purpose of this approach
> was to do something with T inside of the Function() function. Using
> templates so that the function is defined only at the very final
> moment when someone instantiate the Test class with some template
> argument.

I expected something like that. That still gives you the chance, to use
the functions defined inside Test not before the definition of test.

Furthermore you can define a template version of Function outside Test
for this purpose.


Marcel

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 1:03:55 PM7/11/08
to
On Jul 11, 6:53 pm, Marcel Müller <news.5.ma...@spamgourmet.org>
wrote:

> I expected something like that. That still gives you the chance, to use


> the functions defined inside Test not before the definition of test.
>
> Furthermore you can define a template version of Function outside Test
> for this purpose.
>
> Marcel

Can you explain this point better? Especially the last sentence. If I
define a template version of Function() then I would not be able to
call it from main, am I wrong? Can you provide an example? Thank you.

Victor Bazarov

unread,
Jul 11, 2008, 1:21:46 PM7/11/08
to
H9XLrv5o...@spambox.us wrote:
> [..]

> So does it mean that my syntax of function injection is standard-
> compliant? And do you know of a way to accomplish the same thing
> within the template class?

From all I could gather by reading the Standard and other posts, there
is nothing wrong with your code even when the template is involved.
[temp.friend]/5 says:
<quote>
When a function is defined in a friend function declaration in a class
template, the function is defined at each instantiation of the class
template. The function is defined even if it is never used. The same
restrictions on multiple declarations and definitions which apply to
non-template function declarations and definitions also apply to these
implicit definitions.
</quote>

The function is inline (implicitly), it's defined (per that paragraph)
when you instantiate your template.

VC++ 9 (Visual Studio 2008) chokes on the module throwing C1001 (ICE) on
the line that contains the friend declaration. Why, I don't know. I do
not know whether it's been already reported as a bug, either. I'll ask
in the Visual C++ newsgroup. As for GCC, you would have to ask them.
Comeau C++ (online) compiles it fine; it doesn't link, so I am not sure
if everything's OK with their ability to handle that code.

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 1:34:46 PM7/11/08
to
On Jul 11, 7:21 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:

So my code involving the template class and function injection is
correct and standard-compliant.

As for GCC it compiles the code just fine but as I said it doesn't
link it because it misses the Function() function. It says that's not
defined.
Now I don't know if this is due to the function definition for some
reason not "matching" the declaration (for instance because it is
treated like a template function) or because somehow the function body
is completely "skipped" (for instance because the function gets
inlined).
From what I know a function gets inlined only when declaration and
definition occur in the same place, which is not true for my code.
So is there any possibility that this is a GCC bug?

Victor Bazarov

unread,
Jul 11, 2008, 1:53:07 PM7/11/08
to
H9XLrv5o...@spambox.us wrote:
> [..]

> So my code involving the template class and function injection is
> correct and standard-compliant.

Yes, IMNSHO.

> As for GCC it compiles the code just fine but as I said it doesn't
> link it because it misses the Function() function. It says that's not
> defined.
> Now I don't know if this is due to the function definition for some
> reason not "matching" the declaration (for instance because it is
> treated like a template function) or because somehow the function body
> is completely "skipped" (for instance because the function gets
> inlined).

You probably can examine the contents of the object code (.o file) and
find out what functions you have defined there. I would be you have at
least 'main'. <Unix> RTFM about 'nm' (IIRC) utility. </Unix>

> From what I know a function gets inlined only when declaration and
> definition occur in the same place, which is not true for my code.

Is that code different from what you posted?

> So is there any possibility that this is a GCC bug?

Bug? In GCC?! Nah...

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 2:09:50 PM7/11/08
to
On Jul 11, 7:53 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:

> H9XLrv5oXVNvH...@spambox.us wrote:
> > [..]
> > So my code involving the template class and function injection is
> > correct and standard-compliant.
>
> Yes, IMNSHO.
>
> > As for GCC it compiles the code just fine but as I said it doesn't
> > link it because it misses the Function() function. It says that's not
> > defined.
> > Now I don't know if this is due to the function definition for some
> > reason not "matching" the declaration (for instance because it is
> > treated like a template function) or because somehow the function body
> > is completely "skipped" (for instance because the function gets
> > inlined).
>
> You probably can examine the contents of the object code (.o file) and
> find out what functions you have defined there. I would be you have at
> least 'main'. <Unix> RTFM about 'nm' (IIRC) utility. </Unix>
>

Yes, the problem is that on windows with mingw at least the object
files are outputted on the temporary folder and deleted as far as the
compilation fails. I guess there's some kind of command-line argument
to tell gcc not to delete them or to put them somewhere I say it to,
but I'm not very used to gcc so I'll have to find it out.

> > From what I know a function gets inlined only when declaration and
> > definition occur in the same place, which is not true for my code.
>
> Is that code different from what you posted?
>

I don't understand the question. I'm talking about the code I posted,
which doesn't compile as well as my real code I'm working on.

> > So is there any possibility that this is a GCC bug?
>
> Bug? In GCC?! Nah...
>

Well if Bush became president 2 consecutive times, everything is
possible.

Victor Bazarov

unread,
Jul 11, 2008, 2:16:28 PM7/11/08
to
H9XLrv5o...@spambox.us wrote:
> On Jul 11, 7:53 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
>> H9XLrv5oXVNvH...@spambox.us wrote:
>>> [..]
>>> From what I know a function gets inlined only when declaration and
>>> definition occur in the same place, which is not true for my code.
>> Is that code different from what you posted?
>>
>
> I don't understand the question. I'm talking about the code I posted,
> which doesn't compile as well as my real code I'm working on.

I wasn't sure whether you meant the code you posted or some other code
in which the template and its explicit instantiation were in a different
(than 'main') translation unit. Can you try your code on a different
compiler? I am going to try in GCC on Linux. Will report with results
in a few minutes...

Victor Bazarov

unread,
Jul 11, 2008, 2:33:05 PM7/11/08
to
Victor Bazarov wrote:
> H9XLrv5o...@spambox.us wrote:
>> On Jul 11, 7:53 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
>>> H9XLrv5oXVNvH...@spambox.us wrote:
>>>> [..]
>>>> From what I know a function gets inlined only when declaration and
>>>> definition occur in the same place, which is not true for my code.
>>> Is that code different from what you posted?
>>>
>>
>> I don't understand the question. I'm talking about the code I posted,
>> which doesn't compile as well as my real code I'm working on.
>
> I wasn't sure whether you meant the code you posted or some other code
> in which the template and its explicit instantiation were in a different
> (than 'main') translation unit. Can you try your code on a different
> compiler? I am going to try in GCC on Linux. Will report with results
> in a few minutes...

Tried it with GCC 4.2.3 on Ubuntu. Here's the output:

Ubuntu-bazarov:~$ g++ test_template.cpp
/tmp/ccCNJWBg.o: In function `main':
test_template.cpp:(.text+0x12): undefined reference to `Function()'
collect2: ld returned 1 exit status
Ubuntu-bazarov:~$ g++ -c test_template.cpp -o test_template.o
Ubuntu-bazarov:~$ nm test_template.o
U _Z8Functionv
U __gxx_personality_v0
00000000 T main
Ubuntu-bazarov:~$

As we can see, the function 'Function' does not get defined in the
module although the template Test is instantiated. That looks like an
oversight on GCC part :*)

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 2:44:25 PM7/11/08
to
On Jul 11, 8:33 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> Victor Bazarov wrote:

Ok, so the function gets probably inlined? Could you try to copy/paste
the printf() call many times so that the compiler doesn't inline it?
Or is there somethin for not making GCC inline a function? I know on
MSVC there's the __declspec(noinline) but I don't know if GCC has some
equivalent (I guess it does though).

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 2:51:02 PM7/11/08
to
Also, I tried this on Open Watcom and it compiles and link it without
any problem and the executable works of course.

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 2:57:42 PM7/11/08
to

Nop, even with the attribute __attribute__ ((noinline)) it still gives
that error about Function() not being defined.

Marcel Müller

unread,
Jul 11, 2008, 3:27:40 PM7/11/08
to

template <typename T>
void Function(const T& arg);

template <typename T>
class Test
{
public:

friend void Function<T>(const T&);
};

template <typename T>
void Function(const T& arg)
{ printf("Function()"); getchar(); }

int main(int argc, char* argv[])
{

Function(Test<int>());
}


But from your question I guess that you want to do something entirely
different. You want to control by the statement
template class Test<int>;
which version of Function is implemented, isn't it? The argument list of
Function does not depend on T at all, but the body does. This is evil.
Think what is happening if you write
template class Test<int>;
template class Test<char>;

You will get an error in this case, but only if both of them are defined
in the same module. Otherwise you violate the ODR and get undefined
behavior.

In this case a simple
typedef int myFunctionType;
would do a better job.


Marcel

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 5:51:34 PM7/11/08
to
On Jul 11, 9:27 pm, Marcel Müller <news.5.ma...@spamgourmet.org>
wrote:

Yes I know most of the times this would be seen as a bad design choice
but in this case is instead a perfect solution to a problem because I
know as a design principle that the Test class template will never be
instantiated more than one time so there won't be any duplicate
definition of Function(). Also if you follow the conversation with
Victor Bazarov he informed me that my code is completely standard-
compliant thus making this a possible GCC bug. I've also double-
checked that this code compiles and links fine on the Open Watcom
compiler.

H9XLrv5o...@spambox.us

unread,
Jul 11, 2008, 6:20:55 PM7/11/08
to
On Jul 11, 8:51 pm, H9XLrv5oXVNvH...@spambox.us wrote:
> Also, I tried this on Open Watcom and it compiles and link it without
> any problem and the executable works of course.

Furthermore I was wrong about having a way to compile this code in
visualc++. In fact that code was slightly different and visualc++
seems not only unable to compile any kind of code like this, but it
also crashes when you try to make it to.
So basically so far the only compiler able to compile this kind of
code seems to be this Open Watcom.

0 new messages