For the following code from Bjarne's book, it is stated that template parameter T for function g will be instantised as int other than double. My question is why there are not two instantiations for both int and double version of template function g?

Code:

// section C.13.8.3 Point of Instantiatant Binding

template <class T> void f (T a) { g(a); }

void g(int);

void h()
{
extern g (double);
f (2);
}

Here is the related statement from Bjarne,

--------------------
Each use of a template for a given set of template arguments defines a point of instantiation.
That point is the nearest global or namespace scope enclosing its use,
just before the declaration that contains that use.
--------------------

Does it before g (double) is not global function or namespace scope enclosing its use? If yes, I do not know why g (double) is not a global function, since it is declared as extern and some other compile unit should expose it?

thanks in advance,
George

03-06-2008

CornedBee

Uh, what? g isn't a template function, and the example as given is unambiguous. It's also not what's in my version of TC++PL. Are you sure you've reproduced it correctly?

03-06-2008

George2

Hi CornedBee,

Are you challenging g(int) is not be able to instantise template function f to f(int)? Bjarne said it could...

Refer to the book The C++ Programming Language, section C.13.8.3 Point of Instantiatant Binding.

Any comments?

Quote:

Originally Posted by CornedBee

Uh, what? g isn't a template function, and the example as given is unambiguous. It's also not what's in my version of TC++PL. Are you sure you've reproduced it correctly?

regards,
George

03-06-2008

CornedBee

I have referred to it, but what you presented is an incorrect rendition of the example Bjarne gave. Perhaps your earlier edition had such an error, but I doubt it. Are you sure you've faithfully copied the example out?

03-06-2008

robatino

George2's example is exactly what I have in my copy of TC++PL (9th printing, January, 1999).

Edit: 3rd edition

03-06-2008

matsp

The example matches my 3rd Edition of TC++PL book - but it may be different in a more recent printing of the book.

--
Mats

03-06-2008

laserlight

Perhaps the code example is the same, but does the text say something to the effect of "template parameter T for function g will be instantised as int other than double"?

03-06-2008

CornedBee

OK, since the earlier prints are in error, I'll post what's in the 15th printing and explain the issue. Please note, however, that the example as given is still incorrect. (WTH was Stroustrup thinking when he wrote this?)

C.13.8.3 says:

Quote:

Each use of a template for a given set of template arguments defines a point of instantiation. That point is in the nearest global or namespace scope enclosing its use, just before the declaration that contains that use. Fore example:

Here, the point of instantiation for f is just before h(), so the g() called in f() is the global g(X) rather than the local g(int).

OK, so I pointed out that the comment is wrong. The line invokes f<int>(2), not f<X>(X(2)). However, that's not the point anyway.

The point is that f<int>(2) in turn does not call g(int), which according to overloading rules is the best choice, but g(X) via the implicit conversion int->X. The reason is that the point of instantiation for f<int> is just before h(). So with the instantiation made explicit, the example looks like this:

Note that the implementation of f<int> doesn't see the declaration of g(int). All it sees is the declaration of g(X). Therefore, g(int) is never considered, and g(X) is called.

That's the entire issue.

03-06-2008

George2

Hi CornedBee,

I have read your great reply. Still not sure 100&#37; grasp your points, since mixed reading of both your points and Bjarne's. Let me confirm three points before further discussion. Please let me know your points other than Bjarne's.

1. function f is instantised to f<int> or f<X>?

2. the invocation of f(2) inside main will invoke f<X> or f<int>?

3. inside functon f, g(a) will call g(int) or g(X)?

It is appreciated if you could provide your definite answer to the 3 small questions. :-)

Quote:

Originally Posted by CornedBee

OK, since the earlier prints are in error, I'll post what's in the 15th printing and explain the issue. Please note, however, that the example as given is still incorrect. (WTH was Stroustrup thinking when he wrote this?)

C.13.8.3 says:

OK, so I pointed out that the comment is wrong. The line invokes f<int>(2), not f<X>(X(2)). However, that's not the point anyway.

The point is that f<int>(2) in turn does not call g(int), which according to overloading rules is the best choice, but g(X) via the implicit conversion int->X. The reason is that the point of instantiation for f<int> is just before h(). So with the instantiation made explicit, the example looks like this:

Note that the implementation of f<int> doesn't see the declaration of g(int). All it sees is the declaration of g(X). Therefore, g(int) is never considered, and g(X) is called.

That's the entire issue.

regards,
George

03-06-2008

Elysia

Quote:

Originally Posted by George2

1. function f is instantised to f<int> or f<X>?

f<int>

Quote:

2. the invocation of f(2) inside main will invoke f<X> or f<int>?

f<int>

Quote:

3. inside functon f, g(a) will call g(int) or g(X)?

g<X>

03-06-2008

George2

Hi Elysia,

Why the following code block will instantise f to f<int> other than f<X>? You can see g's input parameter type is X.

Code:

struct X { X(int); /* ... */ };

void g(X);

template <class T> void f(T a) { g(a); }

Quote:

Originally Posted by Elysia

f<int>

f<int>

g<X>

regards,
George

03-06-2008

Elysia

Why would it instantiate to f<X> when f<int> is a better choice? You pass int, therefore it deduces the type to int. It's simple - the compiler tries a non-implicit cast solution first.

03-06-2008

CornedBee

Or in other words, what does f's content have to do with its instantiation?

03-06-2008

George2

Hi Elysia,

1.

Code:

f(2);

2.

Code:

void g(X);

Quote:

Originally Posted by Elysia

Why would it instantiate to f<X> when f<int> is a better choice? You pass int, therefore it deduces the type to int. It's simple - the compiler tries a non-implicit cast solution first.

(1) will instantise f to int and (2) will instantise f to X, and (2) is shown before (1).

My question is,

1. how do you think (1) will work and (2) will not work? How do you prove it?

2. if you prove it, well, the rule will be more complex. The rule is not the nearest e.g. g(X) will instantise the temlpate function, right?

Thanks CornedBee,

Could you provide more information about what do you mean "f's content have to do with its instantiation" please? Do you mean the definition or declaration of g will not trigger instantiation of function f or something else? More information please?

Quote:

Originally Posted by CornedBee

Or in other words, what does f's content have to do with its instantiation?

regards,
George

03-07-2008

Elysia

Quote:

Originally Posted by George2

(1) will instantise f to int and (2) will instantise f to X, and (2) is shown before (1).

My question is,

1. how do you think (1) will work and (2) will not work? How do you prove it?

2. if you prove it, well, the rule will be more complex. The rule is not the nearest e.g. g(X) will instantise the temlpate function, right?

Thanks CornedBee,

Could you provide more information about what do you mean "f's content have to do with its instantiation" please? Do you mean the definition or declaration of g will not trigger instantiation of function f or something else? More information please?

If you listen, you'll know that the compiler will not deduce a template type depending on the contents of the function itself. So whatever you may rename g to, and whatever type it may take, whether or not the compiler can send a type to it with or without implicit conversions, it will still deduce the type of T depending on the arguments you pass to the function.

In this case, the compiler can pass int directly instead of performing an implicit conversion to X. Therefore it will always instantiate f<int>.