|
|
|
|
|
|
| |
| |
|
|
From: Fredrik Eriksson
Subject: Re: A question about Java generics (not a flame)
Date: 15 May 2008 13:06:12
Message: <op.ua7ggm1d7bxctx@e6600>
|
|
|
| |
| |
|
|
On Thu, 15 May 2008 14:49:55 +0200, Warp <war### [at] tagpovrayorg> wrote:
> Fredrik Eriksson <fe79}--at--{yahoo}--dot--{com> wrote:
>> Now make a small change to main.cpp:
>
>> // main.cpp
>> export template <typename T> void f();
>
>> #include "g.hpp"
>> template <> void g(int i) { /* Do something completely different */ }
>
>> int main(){ f<int>(); }
>> // end main.cpp
>
> I don't see how this causes a problem described earlier. This simply
> requires main.cpp to be recompiled (after all, it's the one which has
> been changed), which will result in a new object file which does not
> use the export template.
What? The exported template 'f' is still used. Only 'g' is changed.
> Why would this cause the need to recompile the export template for
> each usage in the program?
It forces the exported template to be recompiled whenever you change any
translation unit that instantiates it.
--
FE
Post a reply to this message
|
|
| |
| |
|
|
From: Fredrik Eriksson
Subject: Re: A question about Java generics (not a flame)
Date: 15 May 2008 13:11:45
Message: <op.ua7gptbl7bxctx@e6600>
|
|
|
| |
| |
|
|
On Thu, 15 May 2008 18:12:17 +0200, Warp <war### [at] tagpovrayorg> wrote:
>> foo.cc:
>> export template<typename T>
>> void foo(T t) { bar(t); }
>
>> I see how that could make some difference.
>
> OTOH, thinking about it: There's no function named 'bar' defined
> anywhere in the scope of foo.cc, so why should that even compile?
'bar' is a dependent name, and must therefore be looked up in both the
definition context and the instantiation context.
> I have to admit I don't know if the C++ standard requires the
> environment of the instantation of the template when compiling the
> template function or not.
When parsing the template definition, only non-dependent names are looked
up. Dependent names are looked up at the instantiation point; at that
point both contexts are needed.
--
FE
Post a reply to this message
|
|
| |
| |
|
|
From: Warp
Subject: Re: A question about Java generics (not a flame)
Date: 16 May 2008 02:46:09
Message: <482d2db1@news.povray.org>
|
|
|
| |
| |
|
|
Warp <war### [at] tagpovrayorg> wrote:
> foo.cc:
> export template<typename T>
> void foo(T t) { bar(t); }
> a.cc:
> export template<typename T>
> void foo(T t);
> void bar(int i);
> void a() { foo(5); }
> b.cc:
> export template<typename T>
> void foo(T t);
> void bar(long i);
> void b() { foo(5); }
> I see how that could make some difference.
Actually this isn't as simple after all. I made some tests with gcc,
and I'm getting rather curious results.
In one file I have this:
// ----- file1.cc -----
#include <iostream>
template<typename T>
void foo(T t)
{
bar(t);
}
void bar(int i) { std::cout << "int: " << i << std::endl; }
void b();
int main()
{
foo(5);
b();
}
// --------------------
And in another file I have this:
// ----- file2.cc -----
#include <iostream>
template<typename T>
void foo(T t)
{
bar(t);
}
void bar(long i) { std::cout << "long: " << i << std::endl; }
void b()
{
foo(7);
}
// --------------------
When I run this program I get the expected result:
int: 5
long: 7
However, this happens because gcc is inlining the template function in
both cases. If I stop it from being able to inline the function, curious
things happen. This can be done, for example, by adding a static variable
inside the function, so that the function becomes, in both cases:
template<typename T>
void foo(T t)
{
static int count = 0;
std::cout << "count: " << ++count << std::endl;
bar(t);
}
Now, what do you think the output is? Rather surprisingly:
count: 1
int: 5
count: 2
int: 7
Which one of the two instances of foo() is called depends on which .cc
file is specified first. The other one is ignored.
This is even so if the implementations of foo() are different (which answers
that question). For example, if I make the one in the first file like this:
template<typename T>
void foo(T t)
{
static int count = 0;
std::cout << "count(1): " << ++count << std::endl;
bar(t);
}
and the second one like this:
template<typename T>
void foo(T t)
{
static int count = 0;
std::cout << "count(2): " << ++count << std::endl;
bar(t);
}
the output will be:
count(1): 1
int: 5
count(1): 2
int: 7
Only the first foo() function is used, the second one is completely
ignored.
I have to admit I don't know if gcc is behaving correctly here. However,
I can see how this could be the case also with export templates: Even if
the context of the instantiation changes, it might not matter. It may still
be so that only one instantiation is used throughout the program (and thus
the export template has to be compiled once even if it's instantiated several
times).
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
From: Warp
Subject: Re: A question about Java generics (not a flame)
Date: 16 May 2008 09:16:07
Message: <482d8917@news.povray.org>
|
|
|
| |
| |
|
|
Fredrik Eriksson <fe79}--at--{yahoo}--dot--{com> wrote:
> > I have to admit I don't know if the C++ standard requires the
> > environment of the instantation of the template when compiling the
> > template function or not.
> When parsing the template definition, only non-dependent names are looked
> up. Dependent names are looked up at the instantiation point; at that
> point both contexts are needed.
Actually that's not what the C++ standard says. This is the relevant
part of the standard:
A specialization for a function template, a member
function template, or of a member function or static
data member of a class template may have multiple points
of instantiations within a translation unit. A
specialization for a class template has at most one
point of instantiation within a translation unit. A
specialization for any template may have points of
instantiation in multiple translation units. If two
different points of instantiation give a template
specialization different meanings according to the one
definition rule (3.2), the program is ill-formed, no
diagnostic required.
In short: If the context causes a template instantiation to produce
different results, the program is ill-formed. In other words, the
result is undefined behavior, and the compiler can do whatever it wants.
I understand this to also mean that the compiler is allowed to compile
an export template just once even if it's instantiated at several places,
using the context of one of those places.
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On Fri, 16 May 2008 15:16:07 +0200, Warp <war### [at] tagpovrayorg> wrote:
> Fredrik Eriksson <fe79}--at--{yahoo}--dot--{com> wrote:
>> When parsing the template definition, only non-dependent names are
>> looked
>> up. Dependent names are looked up at the instantiation point; at that
>> point both contexts are needed.
>
> Actually that's not what the C++ standard says.
Oh yes it is. Check sections 14.6.3 & 14.6.4.
> This is the relevant part of the standard:
>
> A specialization for a function template, a member
> function template, or of a member function or static
> data member of a class template may have multiple points
> of instantiations within a translation unit. A
> specialization for a class template has at most one
> point of instantiation within a translation unit. A
> specialization for any template may have points of
> instantiation in multiple translation units. If two
> different points of instantiation give a template
> specialization different meanings according to the one
> definition rule (3.2), the program is ill-formed, no
> diagnostic required.
>
> In short: If the context causes a template instantiation to produce
> different results, the program is ill-formed. In other words, the
> result is undefined behavior, and the compiler can do whatever it wants.
What the paragraph (from section 14.6.4.1) says is that if a particular
template specialisation is instantiated in more than one place then those
instantiations must have the same meaning.
In the example I posted there is only one instantiation point for 'f'; the
ODR is irrelevant there.
> I understand this to also mean that the compiler is allowed to compile
> an export template just once even if it's instantiated at several places,
> using the context of one of those places.
Only if all those places use the exact same template specialisation. Note
that this would require the compiler/linker to remember which translation
units use which exported templates, since the exported template must still
be recompiled if all of the relevant contexts change. Also note that the
linker would have to verify that at least one of the translation units
having an "unchanged" context actually gets linked in; if not, the
template would have to be recompiled.
--
FE
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On Fri, 16 May 2008 08:46:09 +0200, Warp <war### [at] tagpovrayorg> wrote:
> Warp <war### [at] tagpovrayorg> wrote:
>
> In one file I have this:
>
> // ----- file1.cc -----
> #include <iostream>
>
> template<typename T>
> void foo(T t)
> {
> bar(t);
> }
>
> void bar(int i) { std::cout << "int: " << i << std::endl; }
>
> void b();
>
> int main()
> {
> foo(5);
> b();
> }
> // --------------------
>
> And in another file I have this:
>
> // ----- file2.cc -----
> #include <iostream>
>
> template<typename T>
> void foo(T t)
> {
> bar(t);
> }
>
> void bar(long i) { std::cout << "long: " << i << std::endl; }
>
> void b()
> {
> foo(7);
> }
> // --------------------
Your example is ill-formed according to the very paragraph you yourself
quoted in another post. You have multiple instantiations of 'foo<int>',
but they have different meanings. Also, since the overloads of 'bar' are
spread out, section 14.6.4.2 applies as well:
"If the call would be ill-formed or would find a better match had the
lookup within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in all
translation units, not just considering those declarations found in the
template definition and template instantiation contexts, then the program
has undefined behavior."
> I have to admit I don't know if gcc is behaving correctly here.
In this case it does not matter, as the example is ill-formed. Note
however that few C++ compilers correctly implement two-phase lookup.
--
FE
Post a reply to this message
|
|
| |
| |
|
|
From: Warp
Subject: Re: A question about Java generics (not a flame)
Date: 17 May 2008 04:36:31
Message: <482e990e@news.povray.org>
|
|
|
| |
| |
|
|
Fredrik Eriksson <fe79}--at--{yahoo}--dot--{com> wrote:
> > I understand this to also mean that the compiler is allowed to compile
> > an export template just once even if it's instantiated at several places,
> > using the context of one of those places.
> Only if all those places use the exact same template specialisation. Note
> that this would require the compiler/linker to remember which translation
> units use which exported templates, since the exported template must still
> be recompiled if all of the relevant contexts change. Also note that the
> linker would have to verify that at least one of the translation units
> having an "unchanged" context actually gets linked in; if not, the
> template would have to be recompiled.
Sorry, I still don't understand this.
I tried my foo-bar example making the bar() function a template which was
specialized in one of the compilation units but not the other, and at least
gcc still behave in the same way: When foo() was not inlined, only one
version of bar() was called: The specialized version was never called.
From what you have written it sounds like the compiler would have to
always call the specialized bar() template if it is in the context of
the foo() instantiation, but at least gcc doesn't behave this way (and,
frankly, I don't know *how* it could behave that way without seriously
messing things up).
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On Sat, 17 May 2008 10:36:31 +0200, Warp <war### [at] tagpovrayorg> wrote:
> Sorry, I still don't understand this.
>
> I tried my foo-bar example making the bar() function a template which
> was
> specialized in one of the compilation units but not the other, and at
> least
> gcc still behave in the same way: When foo() was not inlined, only one
> version of bar() was called: The specialized version was never called.
Your foo-bar example is ill-formed. The compiler can do whatever it wants.
> From what you have written it sounds like the compiler would have to
> always call the specialized bar() template if it is in the context of
> the foo() instantiation, but at least gcc doesn't behave this way (and,
> frankly, I don't know *how* it could behave that way without seriously
> messing things up).
It is commonly called "two-phase lookup" (though it is not named as such
in the standard) and is explained in section 14.6 [temp.res] of the
standard. Section 14.6.4 [temp.dep.res] deals specifically with dependent
name resolution.
Compiler writers have been rather slow in implementing two-phase lookup
properly, almost as slow as with implementing 'export'.
--
FE
Post a reply to this message
|
|
| |
| |
|
|
From: Warp
Subject: Re: A question about Java generics (not a flame)
Date: 17 May 2008 07:41:18
Message: <482ec45e@news.povray.org>
|
|
|
| |
| |
|
|
Fredrik Eriksson <fe79}--at--{yahoo}--dot--{com> wrote:
> On Sat, 17 May 2008 10:36:31 +0200, Warp <war### [at] tagpovrayorg> wrote:
> > Sorry, I still don't understand this.
> >
> > I tried my foo-bar example making the bar() function a template which
> > was
> > specialized in one of the compilation units but not the other, and at
> > least
> > gcc still behave in the same way: When foo() was not inlined, only one
> > version of bar() was called: The specialized version was never called.
> Your foo-bar example is ill-formed. The compiler can do whatever it wants.
How is it different from your example, which you gave earlier? Also you
had a template function calling another template function, and the latter
being specialized in the context of instantiating the former. That's exactly
what I did.
--
- Warp
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On Sat, 17 May 2008 13:41:18 +0200, Warp <war### [at] tagpovrayorg> wrote:
> Fredrik Eriksson <fe79}--at--{yahoo}--dot--{com> wrote:
>> Your foo-bar example is ill-formed. The compiler can do whatever it
>> wants.
>
> How is it different from your example, which you gave earlier? Also you
> had a template function calling another template function, and the latter
> being specialized in the context of instantiating the former. That's
> exactly what I did.
The difference is that you are instantiating 'foo<int>' in more than one
place. When you do that, the instantiations must have the same meaning or
the program is ill-formed. In my example 'f<int>' is only instantiated
once. That example was intented only to demonstrate why an exported
template must be recompiled when code that uses it is changed.
--
FE
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
|
|