8
votes

Consider the below code:

#include <iostream>
template<typename T>
struct Test{
    template<typename U>
    static U value;
};
template<typename T>
template<typename U>
U Test<T>::value = U{};
//#1
int main(){
    auto d = Test<int>::value<int>;
}
//#2

The [temp.point] section in the standard covers the most case of where the point of instantiation shall place. However I think it's unclear about static data member template, due to:

temp.point#1

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.

temp.point#4

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.

Two paragraphs all respectively cover the case they mentioned, they are a specialization for static data member of a class template and a class member template specialization, So, the specialization for static data member template could be called a specialization for static data member of a class template or a class member template specialization? I prefer to consider it as a class member template specialization, My reason is in the first paragraph, it has mentioned a member function template specialization, that implies if A is a specialization for X template, it would call it a X template specialization, however It's just my inference.

In the section of [temp.static], it implies that a static data member and static data member template are collectively called static data member of class or class template.

temp.static#1

A definition for a static data member or static data member template may be provided in a namespace scope enclosing the definition of the static member's class template.

[Note: A specialization of a static data member template is a static data member. A specialization of a member function template is a member function. A specialization of a member class template is a nested class.  — end note]

Now, the wording makes the question more unclear. So according to the above rules, Is the point of instantiation for Test<int>::value<int> is at #2 or #1?

If the POI of Test<int>::value<int> is at #2, then it will be considered as a specialization for static data member of a class template, otherwise if it's at #1, then it will be considered as a class member template specialization, I don't know which the position is correct. If I miss something, please correct me.

2
What's unclear about last statement? You may provide specialization within namespace scope or as a fully qualified name ANamespace::Test<T>::valueSwift - Friday Pie
@SwiftFridayPie Please read the question.xmh0511

2 Answers

1
votes

You may be confusing instantiation/specialization

template<typename T>
template<typename U>
U Test< T >::value = 88;  // <- this is not specialization 

template<>
template<>
int Test< int >::value<int> = 98;  // <- this is specialization

Run this code https://godbolt.org/z/h434eG, take a look at the order of the numbers on the output, then uncomment the block with a specialization and run again.

-1
votes

The point of Cleiton Santoia Silva is that there is no explicit member template specialisation. But if you read temp.inst#3:

Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

We still get a specialization which is triggered by the template usage in main. I would say to "virtual specialization", because it is not visible in the code. This results exaclty like if there would be an explicit specialization.

But the question is where would the compiler write this specialization - which is defined in [temp.point]. But by which paragraph? If you read carefully paragraph 4 you can see it has an additional condition (the otherwise is related to the inner / second if):

...if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is

Is the member function template referenced by the class template "Test"? No, it is only referenced inside main. So, we don't need to look at this paragraph.

But let us look at the first paragraph. There we have nearly the same condition just without "if" but "and":

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

Because the condition is not true we need to look at the "else case":

... Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

This sentence is somehow misleading. What is a namespace scope declaration (I found no definition in the standard)? And which definition is meant here? Your interpretation was that the definition is meant where the template instanciation occured (main). But I don't think so. I Think definition of the template is meant.

So to answer your question: it should be before main (after main would make the program "ill-formed"). But you are right the wording should be improved there.

Btw: You can have a "look inside a C++ compiler" by using cppinsights (here). Unfortunately it seems to work not correctly (in that case) for the implicit global namespace scope. Here you can see where the specializations are "practically" instantiated.


Old Answer

Cleiton Santoia Silva is totally right. Your source code shows just a static template member declaration and a static template member definition. It is no specialization.

Look here

The template instation happens here:

#include <iostream>
template<typename T>
struct Test{
    template<typename U>
    static U value;  //this is a static member template declaration
};
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition

//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;

//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;

int main()
{
    auto d = Test<int> //<- here is Test<int> implicitly instantiated
          ::value<int>; //<- here is the member template ::Test<int>::value<int> implicitly instantiated

    std::cout << Test<char>::value<int> << "\n"; //this prints 42
    std::cout << Test<int>::value<int> << "\n"; //this prints 22
    std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}

If you would write this - your program becomes ill-formed:

#include <iostream>
template<typename T>
struct Test{
    template<typename U>
    static U value;  //this is a static member template declaration
};
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition


int main()
{
    auto d = Test<int> //<- here is Test<int> instantiated
          ::value<int>; //<- here is the member template instantiated

    std::cout << Test<char>::value<int> << "\n"; //this prints 42
    std::cout << Test<int>::value<int> << "\n"; //this prints 22
    std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}

//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;

//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;

But this would be fine. Non inline static member definitions must defined in cpp files to not violate ODR. But like with all templates - every template definition must be available in all translations units. This is reason why such a definition is usually definied in a header:

#include <iostream>
template<typename T>
struct Test{
    template<typename U>
    static U value;  //this is a static member template declaration
};

//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;

//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;

int main()
{
    auto d = Test<int> //<- here is Test<int> implicitly instantiated
          ::value<int>; //<- here is the member template ::Test<int>::value<int> implicitly instantiated

    std::cout << Test<char>::value<int> << "\n"; //this prints 42
    std::cout << Test<int>::value<int> << "\n"; //this prints 22
    std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}

template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition