Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I found out that you can specialize a template after it's first use if you use it using a wrapper template. Simple example:

#include <iostream>

template<typename T>
const char* templateImpl();

template<typename T>
const char* templateGetter() { return templateImpl<T>(); }

struct S{};

int main(){ std::cout << templateGetter<S>() << std::endl; return 0; }

template<>
const char* templateImpl<S>(){ return "S"; }

This works with every compiler - I'm not surprised MSVC compiles it since it handles templates differently, but GCC and clang allow it too. I thought the standard required the specialization to occur before the first use, which in this case would mean before main and expected them to report an error.

Did I miss something, is this code standard compliant?

To clarify, if I change templateGetter<S> to templateImpl<S> in main, the program won't compile with the error message I would expect from this too:

main.cpp:14:29: error: specialization of 'const char* templateImpl() [with T = S]' after instantiation

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
267 views
Welcome To Ask or Share your Answers For Others

1 Answer

You got (un)lucky. This is ill-formed NDR.

[temp.expl.spec]/6-7:

6 If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. [...]

7 The placement of explicit specialization declarations for function templates, class templates, variable templates, member functions of class templates, static data members of class templates, member classes of class templates, member enumerations of class templates, member class templates of class templates, member function templates of class templates, static data member templates of class templates, member functions of member templates of class templates, member functions of member templates of non-template classes, static data member templates of non-template classes, member function templates of member classes of class templates, etc., and the placement of partial specialization declarations of class templates, variable templates, member class templates of non-template classes, static data member templates of non-template classes, member class templates of class templates, etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.

p7 isn't really useful here, but I can't resist quoting it :)

Instantiating templateGetter<S> causes the implicit instantiation of a declaration of templateImpl<S>. You didn't see an error with your code because many implementations like to defer template instantiations until the end of the translation unit when possible, which is a permitted implementation technique. (I'm not going to quote the standardese here, but you'll find that function template specializations have an extra point of instantiation at the end of the translation unit.)

Giving templateGetter a deduced return type will force early instantiation of its body:

template<typename T>
auto templateGetter() { return templateImpl<T>(); }

and voila:

+ g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
main.cpp:14:29: error: specialization of 'const char* templateImpl() [with T = S]' after instantiation
 const char* templateImpl<S>(){ return "S"; }
                             ^
+ clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
main.cpp:14:13: error: explicit specialization of 'templateImpl<S>' after instantiation
const char* templateImpl<S>(){ return "S"; }
            ^
main.cpp:7:32: note: implicit instantiation first required here
auto templateGetter() { return templateImpl<T>(); }
                               ^
1 error generated.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...