Does implicit instantiation a must in an instantiation? [duplicate] - c++

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

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.

I think it's legal. Quoting N4140, [temp.point]:
For a function template specialization, ... 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.
Then in [temp.fct.spec]:
A function instantiated from a function template is called a function
template specialization; so is an explicit specialization of a
function template. ...
In other words, the error won't actually occur until templateGetter() and subsequently the specialization of templateImpl are instantiated, which is how you would expect templates to work.

Related

Point of instantiation of default arguments in a template function

The standard allows function templates to be instantiated after the enclosing namespace-scope declaration or at the end of the translation unit when they are referred to from a non-template context: [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]/8
A specialization for a function template, a member function template,
or of a member function or static data member of a class template may
have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any
such specialization that has a point of instantiation within the
translation unit, the end of the translation unit is also considered a
point of instantiation. A specialization for a class template has at
most one point of instantiation within a translation unit. A
specialization for any template may have points of instantiation in
multiple translation units. If two different points of instantiation
give a template specialization different meanings according to the
one-definition rule, the program is ill-formed, no diagnostic
required.
Now consider this minimal reproducible example:
#include <iostream>
#include <array>
struct A {};
std::array<char, 2> show(float, A)
{
std::cout << "2\n";
return {};
}
template<typename T>
struct Fun {
decltype(show(0, T{})) b;
};
template <typename T>
void func(T, int c = sizeof(Fun<T>{}.b))
{
show(0, T{});
std::cout << c << '\n';
}
int main()
{
func(A{});
}
char show(int, A)
{
std::cout << "1\n";
return {};
}
Both GCC and Clang output 1 2 (godbolt).
Here, the instantiation of func<A> (triggered in main) has two points of instantiation: one immediately after main (and thus before the second show) and another at the end of the translation unit. The first 1 indicates that the compilers to instantiate func<A> at the end of the translation unit. However, the default argument sizeof(Fun<T>{}.b) causes Fun<A> to be instantiated, and the second 2 suggests that Fun<A> is instantiated before the second show.
Now, the point of instantiation of default arguments is specified to be that of func<A>: [temp.point]/2
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.
Hmm ... This seems to suggest that the two numbers should be the same.
I feel I'm missing something here. Is there any detail that I happened to neglect? Or did I make mistakes?
As quoted in the question [temp.point]/8 says:
If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.
According to the one-definition rule two definitions are not the same if function call overload resolution of a name used in the definition will yield different entities defined outside the definition. ([basic.def.odr]/6.2)
Overload resolution of the two calls to show in func<A> and in Fun<A> will choose different function overloads depending on whether func<A>'s point of instantiation is immediately after main or at the end of the translation unit, both of which are allowed points of instantiation.
Therefore the program is ill-formed, no diagnostic required.

Using a template before it's specialized?

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
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.
I think it's legal. Quoting N4140, [temp.point]:
For a function template specialization, ... 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.
Then in [temp.fct.spec]:
A function instantiated from a function template is called a function
template specialization; so is an explicit specialization of a
function template. ...
In other words, the error won't actually occur until templateGetter() and subsequently the specialization of templateImpl are instantiated, which is how you would expect templates to work.

Instantiation of template function overloads

I'm aware that the compiler will not instantiation unused template functions as long as they are not virtual in a class.
In a simple case, if I have two overloaded template functions both of which take the same template arguments, it seems the compiler instantiates both overloads. I guess this is required so that the compiler can perform overload resolution? Are overloads exempt from the lazy-instantiation rule for function templates? I wasn't able to find the relevant text in the standard. Here is an example:
template<typename T>
void foo(T) {zzz}
template<typename T>
void foo(T*) {}
int main()
{
int* blah;
foo(blah);
}
I would expect no compiler error if the first overload was not instantiated, however I get the error.
Live Sample
It seems as though you're expecting only one of those overloads to be instantiated because only one of them will be called, but the compiler clearly has to instantiate both of them in order to determine whether either of them can be called and, if so, which one to use.
The more formal answer is that both templates are candidates because your T can always be pointerised, so both are "used" in that sense:
[C++14: 14.7.1/3]: Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[C++14: 14.7.1/10]: If a function template or a member function template specialization is used in a way that involves overload resolution, a declaration of the specialization is implicitly instantiated (14.8.3).
So, basically:
I guess this is required so that the compiler can perform overload resolution?
Correct.
Your question, however, already stems from a misconception that your first function template can be ignored: it can't be. zzz does not depend on any template parameters so SFINAE is not involved; even if SFINAE were involved, it could not help you with your invalid syntax. So, no matter what you do, that code is ill-formed:
template<typename T>
void nil() {zzz}
// g++ -c -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
// main.cpp: In function 'void nil()':
// main.cpp:2:13: error: 'zzz' was not declared in this scope
// void nil() {zzz}
// ^
(live demo)
That being said, a diagnostic is not required in this case; in particular, Microsoft Visual Studio has historically silently accepted such code:
[C++14: 14.6/8]: Knowing which names are type names allows the syntax of every template to be checked. No diagnostic shall be issued for a template for which a valid specialization can be generated. If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required. If every valid specialization of a variadic template requires an empty template parameter pack, the template is ill-formed, no diagnostic required. If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required. [..]
The same wording may also be found in C++11 and C++03, so this has always been the case. Your misconception is therefore understandable.
Incidentally, your observation regarding virtual functions is also not completely accurate:
[C++14: 14.7.1/11]: An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. The use of a template specialization in a default argument shall not cause the template to be implicitly instantiated except that a class template may be instantiated where its complete type is needed to determine the correctness of the default argument. The use of a default argument in a function call causes specializations in the default argument to be implicitly instantiated.
This is not an answer from the inner question, but it is related about the assumption of the question: "I would expect no compiler error if the first overload was not instantiated, however I get the error."
Sure? so, why this code generate a compiler error?
template<typename T>
void nil(T) {zzz}
template<typename T>
void foo(T*) {}
int main()
{
int* blah;
foo(blah);
}
because nil is not instantiated

Can a single member of a class template be partially specialized?

I came across an interesting point that I wasn't able to explain or find an explanation for. Consider the following template definition (compiled with mingw g++ 4.6.2):
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
Should we want to, we can fully specialize any single member function:
template <>
void Foo<char,int>::f() {}
But partial specialization fails with an "invalid use of incomplete type 'class Foo<...>'" error:
template <typename T, typename S>
void Foo<T,S*>::f()
{
}
template <typename T>
void Foo<T,int>::f()
{
}
And I can't figure out why. Is it a conscious design decision made to avoid some problem I can't foresee? Is it an oversight?
The notion of partial specialization only exists for class templates (described by §14.5.5) and member templates (i.e. members of a template class that are themselves template functions, described by §14.5.5.3/2). It does not exist for ordinary members of class templates, nor does it exist for function templates – simply because it is not described by the Standard.
Now, you might argue that by giving the definition of a partial specialization of a member function, such as
template <typename T>
void Foo<T,int>::f()
{ }
you implicitly define a partial specialization of the class template: Foo<T,int>. That, however, is explicitly ruled out by the Standard:
(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).
(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]
The latter implies that it is impossible to implicitly define a partial specialization by simply giving the definition of one of its members: The very existence of that member would not follow from the definition of the primary template, hence defining it is equivalent to defining a member function that wasn't declared, and that isn't allowed (even with non-template classes).
On the other hand, the notion of explicit specialization (or full specialization, as you call it) exists for member functions of class templates. It is explicitly described by the Standard:
(§14.7.3/1) An explicit specialization of any of the following:
[...]
— member function of a class template
[...]
can be declared by a declaration introduced by template<>; [...]
§14.7.3/14 describes the details:
(§14.7.3/14) A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. [...]
Hence, for explicit specializations of members, the instantiation of the rest of the class template works implicitly – it is derived from the primary template definition, or any partial specializations if defined.
I tried to find a succinct quote from the standard, but I don't think there is one. The fact is, there is no such thing as a partial specialization of a template function (or, for that matter, of a template alias). Only class templates can have partial specializations.
Let's forget about templates for a second. In C++, there is a big difference between class names and function names. There can only be one definition of a class within a given scope. (You can have various declarations, but they all refer to the One True Class.) So the name really identifies the class.
A function name, on the other hand, is a kind of group identity. You can define any number of functions within a scope with exactly the same name. When you use a function name to call a function, the compiler has to figure out which function you really meant by looking at the various possibilities and matching the signature of each of them with the supplied arguments. There's no relationship between the various functions which share a name; they're completely separate entities.
So, no big deal. You knew all this, right? But now let's go back to templates.
The name of a templated class is still unique. Although you can define partial specializations, you have to explicitly specialize the same templated class. This mechanism looks superficially like the function-name resolution algorithm referred to above, but there are significant differences -- one of them is that, unlike function prototypes, you cannot have two class templates in the same scope with different kinds of template parameters.
Templated functions, on the other hand, have no need to define unique names. Templating does not replace the normal function overload mechanism. So when the compiler is trying to figure out what a function name means, it has to consider all templated and non-templated declarations for that function name, resolve the templated ones to a set of template parameter assignments (if possible) and then once it has a list of possible function objects, select the best one with normal overload resolution.
That's quite a different algorithm from the templated class template parameter resolution. Instead of just matching a list of provided template arguments with a list of declared template parameters, which is how it resolves class templates, it has to take each templated function which might possibly match (has at least the right number of parameters, for example); deduce template parameters by unifying the supplied arguments with the template; and then add the resolve specialization to the overload set for a further round of overload resolution.
I suppose it would have been possible to have added partial specialization resolution into that process as well, but the interactions between partial specialization and function overloading strike me as likely to lead to pseudo-magical behaviour. In the event, it wasn't necessary and so there is no such mechanism. (You can fully specialize a function template. Full specialization means that there are no template arguments to deduce, so it's not a problem.)
So that's the scoop: you can't partially specialize a templated function, but there is nothing stopping you from providing any number of function templates with the same name. All of them will be considered in overload resolution, and the best one will win, as usual.
Usually, that's actually sufficient for your overloading needs. You should think about templated functions just the same way you think about normal functions: come up with a way to select the one you want based on the supplied arguments. If you feel you really need to supply template parameters in a function call, rather than having them be deduced, just make the function a (possibly static) member of a templated class, and supply the template arguments to the class.
Hope that helps...
I think that the difference is that when you do the first (valid) explicit specialization of f:
template <>
void Foo<char,int>::f() {}
You are doing an implicit instantiation of Foo<char,int>. But when you try the partial specialization with:
template <typename T>
void Foo<T,int>::f()
{
}
The compiler would need to instantiate implicitly Foo<T,int> before doing the specialization, but it cannot do that because of the T. And it fails.
You can check that is the case with the following code:
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
template <>
void Foo<char,int>::f() //line 11
{}
template <>
class Foo<char,int> //line 15
{};
With g++ it gives the errors:
test.cpp:15:7: error: specialization of ‘Foo<char, int>’ after instantiation
test.cpp:15:7: error: redefinition of ‘class Foo<char, int>’
test.cpp:2:7: error: previous definition of ‘class Foo<char, int>’
With clang++ is a bit clearer:
test.cpp:15:7: error: explicit specialization of 'Foo<char, int>' after instantiation
class Foo<char,int>
^~~~~~~~~~~~~
test.cpp:11:6: note: implicit instantiation first required here
void Foo<char,int>::f()
^

Does casting to a pointer to a template instantiate that template?

static_cast<the_template<int>*>(0) - does this instantiate the_template with type int?
The reason for asking is the following code, which will error at linking time with an undefined reference to check_error<char>(void*, long) with Clang and GCC 4.4.5, indicating that it does not instantiate the template. MSVC and GCC 4.5.1 however compile and link just fine, leading to the believe that it does instantiate the template. However, if you leave out the cast, MSVC and GCC (both 4.4.5 and 4.5.1) will error on check_error<char> only (the wanted behaviour), while Clang will error on both calls. Normally I believe Clang when it comes to conforming stuff, but I wonder:
Which compiler is correct and what does the standard say about it?
#include <type_traits>
template<class T>
void check_error(void*, long);
template<class T>
struct foo{
template<class U>
friend typename std::enable_if<
std::is_same<T,U>::value
>::type check_error(foo<T>*, int){}
};
template struct foo<int>;
int main()
{
check_error<int>(static_cast<foo<int>*>(0), 0);
check_error<char>(static_cast<foo<char>*>(0), 0);
}
It is not the cast that instantiates the class template specialization, but the function call, because the argument triggers ADL . The instantiation is done because the completeness of it may affect the semantics of the program.
That clang does not follow the spec here is known and a PR was sent by me some time ago. See http://llvm.org/bugs/show_bug.cgi?id=9440
n3242 §14.7.1/1
Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3),
the class template specialization is implicitly instantiated when the specialization is referenced in a context
that requires a completely-defined object type or when the completeness of the class type affects the semantics
of the program. The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions,
member classes, static data members and member templates; and it causes the implicit instantiation
of the definitions of member anonymous unions. 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.
It seems to me that static_cast would require the instantiation of the declarations, but not of the definitions (as you are just dealing with pointers).
n3242 §14.6.5/1
Friend classes or functions can be declared within a class template. When a template is instantiated, the
names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation.
I think that it should link, but maybe someone else can interpret better than I can.