9

According to the C++17 standard, [temp.point]/4, emphasis mine,

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.

I don't understand how to interpret this sentence. Elsewhere, when describing name lookup in templates, the standard refers to the "instantiation context" and the "definition context". There, the word "context" seems to mean a particular point in the source text, which determines the set of visible names. Here, I'm not sure if the meaning of "context" is the same. If that is what it means, I'm not sure what it means for it to depend on a template parameter. Does that mean it's inside a template, or does it specifically mean there are still some unbound template parameters from enclosing templates at the point where the compiler decides to instantiate the specialization in question, or something else?

Examples would be appreciated.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312

3 Answers3

4

This context appears inside an enclosing template (from within another template specialization and depends on a template parameter). It must depends on a template parameter of the enclosing template, so it may be a context inside the definition context of the enclosing template.

So I suppose this paragraph could be illustrated by this example:

template<class T> struct A{};
template<class T> struct B{};

//point of instantiation of B<int>
template<class T> void f(){
   A<T> a;    //The context depends on enclosing template parameter T
   B<int> b;  //The context does not depend on a template parameter.
   }
//
void g(){
  f<double>();
  }
//point of instantiation of A<double>
//point of instantiation of f<double>
Oliv
  • 17,610
  • 1
  • 29
  • 72
  • At least as I read things, you need not only the "base" template, but also a specialization of (say) `A` for any of this to apply at all. – Jerry Coffin Jun 28 '19 at 21:28
  • @JerryCoffin A specialization is not necessarily an explicity specialization. Instantiation is the action that generates a specialization. – Oliv Jun 28 '19 at 21:31
  • Yes, but I think it still misses the point. [temp.point] is a sub-part of [temp.dep.res], which is "Dependent name resolution". The point here is about resolving a name that may have been defined differently in the "base" template and a specialized template. – Jerry Coffin Jun 28 '19 at 21:36
  • It's "precedes", not "follows" the namespace scope declaration or definition. – Passer By Jun 29 '19 at 06:18
  • @PasserBy `f` is a function template, so its instantiation point [follows the namespace scope declaration](http://eel.is/c++draft/temp.point#1.sentence-2) – Oliv Jun 29 '19 at 07:41
  • @Oliv Oh, I'm blind. Thought it was a class template. – Passer By Jun 29 '19 at 08:54
  • So, would it be correct to say that the "context from which the specialization is referenced" means the piece of text `A` or `B` that refers to the specialization, as considered within a specialization of an enclosing template? Are there any tricky cases involving nested templates? – Brian Bi Jun 29 '19 at 16:05
  • @Brian. *instantiation context* used to be formaly defined in the C++17 standard: [temp.point]/7(https://timsong-cpp.github.io/cppwp/n4659/temp.point#7). This paragraph has been removed. Moreover I have seen [temp.dep.candidate] has also drastically been changed in such a way that normatively, it is unclear what is happening: [before](https://timsong-cpp.github.io/cppwp/n4659/temp.dep.candidate), [after](http://eel.is/c++draft/temp.dep.candidate). What is happening to the standard? I can't find any mention of that changes in the editor's reports and I don't understant anymore the standard. – Oliv Jun 30 '19 at 17:57
  • @Brian In fact those changes come from the merging of the module TS: [c++ standard draft commit](https://github.com/cplusplus/draft/commit/7f17e32f54b7051e2473468b206bbc0a4f372928#diff-250adbc0f50cd58860d020f0eda13cb8) – Oliv Jun 30 '19 at 18:57
  • @Brian Eureka! I found what happened: [Merging Modules](http://open-std.org/JTC1/SC22/WG21/docs/papers/2019/p1103r3.pdf).... Since then,instantiation context is defined in [module.context]... – Oliv Jun 30 '19 at 19:16
0

[This is really more of an extended comment on @Oliv's answer than an answer in itself.]

[temp.point] is a sub-section of [temp.dep.res], which is "Dependent name resolution".

The point here is that I might have something on this order:

template <class T>
class foo { 
    using name = int;
};

template <>
class foo<float> {
    using name = long;
};

template <class T>
class bar {
   foo<typename T> f; // Point A
};

At point A, the meaning of f::name depends on the T over which bar was instantiated, because instantiating foo over int uses the specialization of foo.

At least as I read things, that's the context (pardon still more overloading of the term) in which the paragraph in question is intended to mean something.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • `foo` is not implicitly instantiated because it is referenced in `bar` template definition. This implicit instantiation is a premise. – Oliv Jun 28 '19 at 21:59
  • @Oliv: The implicit instantiation is really only important for one reason. If we do explicit instantiation, it's clear exactly where the instantiation happened, and from there until the end of scope, any names the instantiation created/brought into scope are now in scope. But when the instantiation is implicit, that's not obvious, so they have to define exactly when/where the implicit instantiation happens, so we know what (in this case) version of `name` will be found at in part of the code. – Jerry Coffin Jun 28 '19 at 23:52
0

"Instantiation context" refers to the point in source code where the instantiation occurs. The standard is defining where that point is for each scenario of instantiation, hence the name "point of instantiation".

The words "context" and "depend" are used colloquially to mean what they mean in English, ie "place in source code" and "determined by" respectively. So necessarily, the construct has to appear inside a template (aka "the context from which the specialization is referenced") in order to depend on some template parameter.

template<typename> struct A {};

// Point of instantiation for A<int>
template<typename T>
struct B
{
    A<int> a1;
    A<T>   a2;  // Depends on T
};

// Point of instantiation for A<char>
// Point of instantiation for B<char>
void foo()
{
    B<char> b;
}

The point (pardon the pun) of such a definition is to define the behaviour of any construct depending on the completeness of a class at a particular point in source code. The rules are deceptively complicated, a case where it matters is Is stateful metaprogramming ill-formed (yet)?

Passer By
  • 19,325
  • 6
  • 49
  • 96