Template instantiation context

J

Juha Nieminen

Assume we have these three files:

//--------------------------------------------------------------
// foo.hh
#include <iostream>

template<typename T>
void foo(T value)
{
static int s = 0;
++s;
std::cout << "value:" << value << ", s:" << s
<< ", externalVar:" << externalVar << std::endl;
}
//--------------------------------------------------------------

//--------------------------------------------------------------
// bar.cc
namespace { const int externalVar = 456; }
#include "foo.hh"

void bar()
{
std::cout << "In bar(): ";
foo(200);
}
//--------------------------------------------------------------

//--------------------------------------------------------------
// test.cc
namespace { const int externalVar = 123; }
#include "foo.hh"

void bar();

int main()
{
std::cout << "In main(): ";
foo(100);
bar();
}
//--------------------------------------------------------------

Now we compile test.cc and bar.cc into an executable program. What
should be the output of this program?
 
A

Alf P. Steinbach

* Juha Nieminen:
Assume we have these three files:

//--------------------------------------------------------------
// foo.hh
#include <iostream>

template<typename T>
void foo(T value)
{
static int s = 0;
++s;
std::cout << "value:" << value << ", s:" << s
<< ", externalVar:" << externalVar << std::endl;
}
//--------------------------------------------------------------

//--------------------------------------------------------------
// bar.cc
namespace { const int externalVar = 456; }
#include "foo.hh"

void bar()
{
std::cout << "In bar(): ";
foo(200);
}
//--------------------------------------------------------------

//--------------------------------------------------------------
// test.cc
namespace { const int externalVar = 123; }
#include "foo.hh"

void bar();

int main()
{
std::cout << "In main(): ";
foo(100);
bar();
}
//--------------------------------------------------------------

Now we compile test.cc and bar.cc into an executable program. What
should be the output of this program?

It's UB.

Btw., please don't formulate real questions so that they sound like homework.

If this question had any other answer than UB I would have believed it to be
homework.


Cheers & hth.,


- Alf
 
J

Juha Nieminen

Alf said:
Btw., please don't formulate real questions so that they sound like
homework.

I don't know if you have seen me posting in this group before, but if
you have, you'd probably know that I have been in the business for long
enough that doing homework is way in the past for me by now... :)

This was a genuine question because I'm not completely sure how
template functions should work with respect to:

a) local static variables
b) variables in the outer scope

My best guess is that one type generates one single function (which,
if duplicated in more than one object file, gets merged by the linker),
in which case the static variable should be unique even when the
function is instantiated in more than one compilation unit. But that
raises the question what happens when the context is different (in this
case, when the variable name in the outer scope refers to different
variables in the two compilation units).

Rather than writing an essay as my question, I kept the post short and
simple.
 
P

Pavel

Alf said:
* Juha Nieminen:

It's UB.

Btw., please don't formulate real questions so that they sound like
homework.

If this question had any other answer than UB I would have believed it
to be homework.
Why? It could be an interview questions but then OP would not be able to
use Internet. I can't see how it could be HW. It looks like a fully
compliant question to me.

-Pavel
 
B

Bo Persson

Juha said:
I don't know if you have seen me posting in this group before, but
if you have, you'd probably know that I have been in the business
for long enough that doing homework is way in the past for me by
now... :)

This was a genuine question because I'm not completely sure how
template functions should work with respect to:

a) local static variables
b) variables in the outer scope

My best guess is that one type generates one single function
(which, if duplicated in more than one object file, gets merged by
the linker), in which case the static variable should be unique
even when the function is instantiated in more than one compilation
unit. But that raises the question what happens when the context is
different (in this case, when the variable name in the outer scope
refers to different variables in the two compilation units).

Rather than writing an essay as my question, I kept the post short
and simple.

By having different meanings for the for the name in the outer scope,
you have violated the One Definition Rule.

A template can be defined in several translation units, but the
meaning must be the same. Here it is not.


Bo Persson
 
A

Alf P. Steinbach

* Pavel:
Why? It could be an interview questions but then OP would not be able to
use Internet. I can't see how it could be HW. It looks like a fully
compliant question to me.

The "What should be the output of this program?" triggered my HW recognition
meter. It is the form of the question, a code example followed by "what does
this do?", which is characteristic of homework and almost never what the author
of the code in question would ask. I ignored the HW meter needle's movement
because if it was homework then there would be a definite answer, not UB. :)


Cheers & hth.,

- Alf
 
C

Classic Wrinwright

g++ -Wall -g bar.cc test.cc produces:
In main(): value:100, s:1, externalVar:456
In bar(): value:200, s:2, externalVar:456
 
J

James Kanze

* Juha Nieminen:

[...]
Btw., please don't formulate real questions so that they sound
like homework.
If this question had any other answer than UB I would have
believed it to be homework.

I'd say that the author would have been enough; Juha's not
exactly new to this group. And I've not seen much homework
which involves separate compilation (or other things essential
when writing real code).
 
J

Juha Nieminen

Classic said:
g++ -Wall -g bar.cc test.cc produces:
In main(): value:100, s:1, externalVar:456
In bar(): value:200, s:2, externalVar:456

Well, I didn't ask what gcc will print (because I can test that
myself). I asked what *should* be printed.

(OTOH, if the value printed for externalVar is indeed UB, then any
value would be as valid as anything else, I suppose.)
 
J

James Kanze

Well, I didn't ask what gcc will print (because I can test
that myself).

Actually, you can't very well, since g++ doesn't define it any
more than the standard does. Thus (on my Linux box):

$ g++ -std=c++98 -pedantic bar.cc test.cc
$ a.out
In main(): value:100, s:1, externalVar:456
In bar(): value:200, s:2, externalVar:456
$ g++ -std=c++98 test.cc bar.cc
$ a.out
In main(): value:100, s:1, externalVar:123
In bar(): value:200, s:2, externalVar:123
$ g++ -std=c++98 -pedantic -O bar.cc test.cc
$ a.out
In main(): value:100, s:1, externalVar:123
In bar(): value:200, s:2, externalVar:456

So there is no correct answer to what g++ will print. (Which is
what undefined behavior is all about.)
I asked what *should* be printed.
(OTOH, if the value printed for externalVar is indeed UB, then
any value would be as valid as anything else, I suppose.)

Anything the compiler does is valid. Including refusing to
compile the code. (IMHO, it wouldn't be that difficult to
detect the problem at link time, and generate an error message
then.)
 

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

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top