Template friend function injection

H

H9XLrv5oXVNvHiUI

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

Marcel Müller

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

H9XLrv5oXVNvHiUI

Obviously you are calling an external version of Function here.


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

gpderetta

On Jul 11, 4:30 pm, (e-mail address removed) wrote:
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,
 
H

H9XLrv5oXVNvHiUI

On Jul 11, 4:30 pm, (e-mail address removed) wrote:


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,

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

H9XLrv5oXVNvHiUI

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


V

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

Marcel Müller

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.

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.

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
 
H

H9XLrv5oXVNvHiUI

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

H9XLrv5oXVNvHiUI

[..]
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.

V

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

H9XLrv5oXVNvHiUI

[..]
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.
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.
Bug? In GCC?! Nah...

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

H9XLrv5oXVNvHiUI

Victor said:
(e-mail address removed) 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 :*)

V

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).
 
H

H9XLrv5oXVNvHiUI

Also, I tried this on Open Watcom and it compiles and link it without
any problem and the executable works of course.
 
H

H9XLrv5oXVNvHiUI

Victor said:
(e-mail address removed) wrote:
(e-mail address removed) 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 :*)

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

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

Marcel Müller

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.

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
 
H

H9XLrv5oXVNvHiUI

On Jul 11, 6:53 pm, Marcel Müller <[email protected]>
wrote:
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.

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

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

H9XLrv5oXVNvHiUI

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top