C++ puzzle

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

C++ puzzle

Post by mcostalba »

In SF evaluation:

https://github.com/mcostalba/Stockfish/ ... aluate.cpp

template evaluate_pieces is defined after the function that calls it: do_evaluate

For some reason this works!

One can say, "yes but you have declared it in advance at the beginning of the file".

But actually, first for a template at instantiation time compiler should already know template definition, secondly even if I change correct declaration:

Code: Select all

  template<PieceType Pt, Color Us, bool Trace>
  Score evaluate_pieces&#40;const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea&#41;;
In something very different, but with same name:

Code: Select all

  template<PieceType Pt, Color Us, bool Trace>
  Score evaluate_pieces&#40;);
It works the same!!

This is really weird even for me, I guess it has to do with two phase look up and the fact that the calling site is itself a template with one of its template parameters 'Trace' that is also a parameter of evaluate_pieces. But I still miss the details and a full clear explanation.

Can someone (with knowledge) fully explain in details what's happening?

P.S: Because I don't like this kind of 'work by magic' behavior I have reshuffled the functions to be defined C-style from bottom to top, so to avoid this weirdness.
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: C++ puzzle

Post by mcostalba »

Actually it has nothing to do with 2 pahse look up. Even this small test code seems to work, and I don't understand why.

Code: Select all

#include <iostream>

template<typename T> int test&#40;);

int main&#40;int, char**) &#123;

  std&#58;&#58;cout << test<int>() << std&#58;&#58;endl;
&#125;

template<typename T> int test&#40;) &#123; return 0; &#125;
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: C++ puzzle

Post by mcostalba »

Ok, after some googling I understood this thing is called POI (point of instantiation) and it is when the compiler instantiates the function template. Contrary to popular belief this is not at template calling site, but the rule is _slightly_ more complex:

Code: Select all

This is the statement from ISO C++ Standard 14.6.4.1 Point of instantiation

1&#41; For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

2&#41; If a function template or member function of a class template is called in a way which uses the definition of a default argument of that function template or member function, the point of instantiation of the default argument is the point of instantiation of the function template or member function specialization.

3&#41; For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the  specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of
instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.

After several failed attempts to parse the above rule, I found some explanations in this nice book (not for beginners):

http://books.google.de/books?id=yQU-Nlm ... &q&f=false

where the author, after trying to explain this brain fart called POI, finally at pag. 149 writes:

"In practice, most compiler delay the actual instantiations of non inline function templates to the end of the translation unit". But also warns that "the standard does not make it clear"...really? :-)
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: C++ puzzle

Post by Rein Halbersma »

mcostalba wrote:Actually it has nothing to do with 2 pahse look up. Even this small test code seems to work, and I don't understand why.

Code: Select all

#include <iostream>

template<typename T> int test&#40;);

int main&#40;int, char**) &#123;

  std&#58;&#58;cout << test<int>() << std&#58;&#58;endl;
&#125;

template<typename T> int test&#40;) &#123; return 0; &#125;
Try and remove the template stuff everywhere in the above code, and you'll discover it still compiles ;-)
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: C++ puzzle

Post by mcostalba »

Rein Halbersma wrote: Try and remove the template stuff everywhere in the above code, and you'll discover it still compiles ;-)
Well this is trivial. This is the usual standard function declaration-definition.

I am talking of something else: template definition shall be already known to compiler at the point of instantiation.
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: C++ puzzle

Post by Rein Halbersma »

mcostalba wrote:
Rein Halbersma wrote: Try and remove the template stuff everywhere in the above code, and you'll discover it still compiles ;-)
Well this is trivial. This is the usual standard function declaration-definition.

I am talking of something else: template definition shall be already known to compiler at the point of instantiation.
Ah so you do realize that templates are different from ordinary functions? Why then do you define them in source files rather than in header files that are included by the translation units that need them?
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: C++ puzzle

Post by mcostalba »

Rein Halbersma wrote: Ah so you do realize that templates are different from ordinary functions?
Have you understood the topic? Can you comment about the specific content of the topic?
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: C++ puzzle

Post by Rein Halbersma »

mcostalba wrote:
Rein Halbersma wrote: Ah so you do realize that templates are different from ordinary functions?
Have you understood the topic? Can you comment about the specific content of the topic?
Your Standard and Vandevoorde & Josuttis quotes contain all the information you need: you are relying on current implementations of POI that are perhaps not entirely conforming to the Standard.

But even if what you are currently doing is actually Standard conforming, it is very unusual and fragile to define templates inside source files. Just do it like the rest of the world and define your templates in headers, and include the headers in the source files that use them. That way, you are never relying on points of instantiation.

Also you explicitly specialize such function templates, but they have very non-intuitively during overload resolution. There are also better ways to do that.
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: C++ puzzle

Post by mcostalba »

Rein Halbersma wrote: Just do it like the rest of the world and define your templates in headers, and include the headers in the source files that use them. That way, you are never relying on points of instantiation.
The header is just a temporary artifact that is removed after preprocessing, here the real thing is not the header per-se but the fact that, using the headers and including them at the beginning of the cpp file you have indirectly reached the net result that templates definitions are parsed before are used: I have changed the code to do that directly, without requiring a header that, again, is just a quick recipe for people not understanding or not caring the underlying issues.

Here the news for me (and for many others I think) is that today I have discovered that a template is not instantiated when is called (as I had always thought) but at a very complicated defined point, called point of instantiation, that, for most compilers and most cases, it ends up at the end of the translation unit.
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: C++ puzzle

Post by Rein Halbersma »

mcostalba wrote:Here the news for me (and for many others I think) is that today I have discovered that a template is not instantiated when is called (as I had always thought) but at a very complicated defined point, called point of instantiation, that, for most compilers and most cases, it ends up at the end of the translation unit.
Templates are a very difficult subject in C++, that's why a very disciplined approach is required. The Vandevoorde & Josuttis book (the first 13 chapters at least) is mandatory reading if you are serious about using them.

Header inclusion is more than a convenient way to let the compiler copy-paste your code into your source. It's a tool of discipline to separate points of definition cleanly from points of instantation.