#include <iostream>
template<typename T>
void func(T){}
template void func<int>(int);
template<>
void func<int>(int){
}
int main(){
}
Consider the above code, Clang and GCC both complain such code is ill-formed, as the below outcome noted.
explicit specialization of 'func<int>' after instantiation
However, I only find the similar rule :
temp.expl.spec#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. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.
I think such code does not violate the above rule, Note the emphasized part, it says implicit instantiation, In my example, such declaration template void func<int>(int); is a explicit instantiation definition rather than the specialization that would case an implicit instantiation, So why the above code is ill-formed? what's the rule in the standard does the above code violate? Please point the rule out. Thanks.
It's a bit fragmented, but the relevant rule here is [temp.spec]/5
For a given template and a given set of template-arguments, [...]
both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the explicit instantiation follows a declaration of the explicit specialization. [...]
Related
The following explicit template instantiation results in compiler frontend segfault under LLVM clang++ 11.0 on x86_64-pc-windows-msvc, using the clang-cl interface with -std=c++17, regardless of optimization level.
A.h
template <typename T>
class A
{
public:
T value;
static constexpr auto address = &A<T>::value;
};
extern template class A<float>;
A.cpp
#include "A.h"
template class A<float>;
Note that since C++17 A::address is an inline variable so ODR-using cannot be a problem here.
The compiler behavior is obviously wrong, I already filed a report at the LLVM bug tracker.
Nevertheless, I am still curious about the actual correctness of the code.
Is it an undefined behavior which is handled incorrectly by the compiler, or the code itself is free of any problems and it's only about the compiler. Personally I don't find anything in the standard at the specification of explicit template instantiations which would suggest that the above code is wrong.
I don't think that the above is ill-formed, am I missing something?
Your example class A
// A.h
#pragma once
template <typename T>
class A {
public:
T value;
static constexpr auto address = &A<T>::value;
};
extern template class A<float>;
// A.cpp
#include "A.h"
template class A<float>;
used e.g. as in the following example (full demo here)
#include <iostream>
#include "A.h"
int main() {
A<float> af{42.F}; // uses explicit instantiation: no implicit instantiation occurs.
A<int> ai{43}; // implicit instantiation.
std::cout << af.*A<float>::address // 42
<< "\n" << ai.*A<int>::address; // 43
}
is well-formed, and it is naturally a (ICE; internal compiler error) compiler bug that the compiler crashes. Unless your own program also contains uncarefully placed explicit specializations (see below) or is otherwise very different from the minimal example above, your own program should likewise be well-formed.
Details
[temp.explicit]/14 requires, for an explicit instantiation declaration [emphasis mine]:
If an entity is the subject of both an explicit instantiation
declaration and an explicit instantiation definition in the same
translation unit, the definition shall follow the declaration. An
entity that is the subject of an explicit instantiation declaration
and that is also used in a way that would otherwise cause an
implicit instantiation in the translation unit shall be the subject
of an explicit instantiation definition somewhere in the program;
otherwise the program is ill-formed, no diagnostic required. [...] An
explicit instantiation declaration shall not name a specialization of
a template with internal linkage.
These requirements are all fulfilled the example above, as are the requirements on the definition of A to precede the explicit definition of a specialization of it as per [temp.explicit]/5.
Finally, [temp.spec]/5 contains the additional requirements that [emphasis mine]:
For a given template and a given set of template-arguments,
(5.1) an explicit instantiation definition shall appear at most once in a program,
(5.2) an explicit specialization shall be defined at most once in a program, as specified in [basic.def.odr], and
(5.3) both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the
explicit instantiation follows a declaration of the explicit
specialization. An implementation is not required to diagnose a
violation of this rule.
(5.1) is fulfilled as the explicit instantiation definition of A<float> is located within a single translation unit (a common ill-formed NDR error is to uncarefully place explicit instantiation definitions in headers, where the header is included in more than a single source file). (5.2) does not apply as there is no explicit specialization of A present (for any specialization), and (5.3) subsequently does not apply as there is no explicit specialization of the A<float> specialization that can conflict with the explicit instantiation definition of the latter.
Finally note that, as per [temp.local]/2, you may use the injected-class-name A when initializing the static data member address of the class template A:
template <typename T>
class A {
public:
T value;
static constexpr auto address = &A::value;
};
This question already has answers here:
Should I declare my function template specializations or is defining them enough?
(2 answers)
Is it safe to place definition of specialization of template member function (withOUT default body) in source file?
(3 answers)
Closed 2 years ago.
I'm working on a codebase which uses the following structure:
a.h:
template<int N> void f();
void b();
a.cpp:
#include "a.h"
template<> void f<1>() {}
int main()
{
b();
}
b.cpp:
#include "a.h"
void b()
{
f<1>();
}
The code appears to build and run correctly.
My question is: is this well-formed, or is it some kind of ill-formed NDR that happens to work?
If building with clang -Wundefined-func-template (this was enabled in my IDE's default settings for clang-tidy) then a warning is produced:
b.cpp:5:2: warning: instantiation of function 'f<1>' required here, but no definition is available [-Wundefined-func-template]
f<1>();
^
./a.h:1:22: note: forward declaration of template entity is here
template<int N> void f();
^
b.cpp:5:2: note: add an explicit instantiation declaration to suppress this warning if 'f<1>' is explicitly instantiated in another translation unit
f<1>();
^
But I am not sure whether to just disable the warning, or make some code change (other than moving the explicit specialization definition to the header file, which would not be preferable for this project).
Following the advice in the warning message and adding an explicit instantiation declaration to the header file (i.e. extern template void f<1>();) caused an error message (implicit instantiation of a specialization before explicit instantiation).
However, adding an explicit specialization declaration template<> void f<1>(); to the header file suppresses the warning. But I am not sure if this is (a) necessary, and/or (b) recommended style.
The program violates [temp.expl.spec]/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.
The function template f is explicitly specialized by template<> void f<1>() {} in b.cpp. But in the translation unit formed from b.cpp and including a.h, the statement f<1>(); would cause an implicit instantiation of the same specialization f<1>, and there is no declaration of the explicit specialization earlier (or anywhere) in the translation unit.
Per the Standard, an explicit specialization is always a distinct thing from an instantiated specialization, since both can never exist for the same primary template and same template arguments. But the program might work anyway because many compilers use the same mangled linker names for template explicit specializations and instantiated specializations.
The clang warning might be because it's legal, though unusual, to implicitly instantiate a function template without a visible definition if the same specialization is explicitly instantiated, not explicitly specialized, elsewhere. So it's suggesting an improvement to make a legal program clearer. I'm not exactly sure if it actually is legal, though. But its suggested explicit instantiation declaration would be a lie, since the specialization is explicitly specialized, not explicitly instantiated.
The program does become valid if you add explicit specialization declarations to the header file for every specialization which will be used.
template<int N> void f();
template<> void f<1>();
There's an example in [temp.over]/5 that matches yours almost exactly, and pronounces it well-formed:
[temp.over]/5 ... [ Example:
template<class T> void f(T); // declaration
void g() {
f("Annemarie"); // call of f<const char*>
}
The call of f is well-formed even if the template f is only declared and not defined at the point of the call. The program will be ill-formed unless a specialization for f<const char*>, either implicitly or explicitly generated, is present in some translation unit. —end example ]
[temp]/7 says:
A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated unless the corresponding specialization is explicitly instantiated in some translation unit; no diagnostic is required.
The standard requires explicit instantiation, so explicit specialization in a.cpp won't make the program well-formed.
A similar question ([temp]/7 treats function templates and member functions of class templates equally) was asked in CWG2138:
It is not clear whether the following common practice is valid by the current rules:
// foo.h
template<typename T> struct X {
int f(); // never defined
};
// foo.cc
#include "foo.h"
template<> int X<int>::f() { return 123; }
// main.cc
#include "foo.h"
int main() { return X<int>().f(); }
which was closed as NAD with the following rationale:
As stated in the analysis [which referred to [temp]/7, among other things], the intent is for the example to be ill-formed, no diagnostic required.
So, the answer is: the program is ill-formed NDR, and this is intended.
Consider the following code snippet:
template <typename>
struct X { };
extern template struct X<int>;
int main()
{
X<int>{};
}
It compiles and links: live example on godbolt.org. I would expect it not to link due to the extern template declaration.
My understanding is that extern template means: "please don't instantiate this particular template specialization in this TU, it will be provided by some other TU and you can link against it".
The examples/descriptions. I've seen on isocpp and cppreference seem to validate my mental model. E.g.
From https://en.cppreference.com/w/cpp/language/class_template:
An explicit instantiation declaration (an extern template) skips implicit instantiation step: the code that would otherwise cause an implicit instantiation instead uses the explicit instantiation definition provided elsewhere (resulting in link errors if no such instantiation exists). This can be used to reduce compilation times by explicitly declaring a template instantiation in all but one of the source files using it, and explicitly defining it in the remaining file.
Why does my code snippet link? What is actually happening here?
EDIT - found this in the latest Standard draft:
[temp.explicit]
If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition in the same translation unit, the definition shall follow the declaration. An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.
Does this mean that the code snippet I posted is ill-formed, NDR?
Why does my code snippet link? What is actually happening here?
Well, there's nothing to link. For one has to consider the effects of the explicit instantiation. From n3337:
[temp.explicit] (emphasis mine)
10 Except for inline functions and class template
specializations, explicit instantiation declarations have the effect
of suppressing the implicit instantiation of the entity to which they
refer. [ Note: The intent is that an inline function that is the
subject of an explicit instantiation declaration will still be
implicitly instantiated when odr-used ([basic.def.odr]) so that the
body can be considered for inlining, but that no out-of-line copy of
the inline function would be generated in the translation unit. — end
note ]
So the implicit instantiation of the class template specialization X<int>, is not suppressed. It's also an aggregate, so its initialization occurs inline, and we get nothing to link against. However, if it had any members, those would be suppressed under paragraph 8:
An explicit instantiation that names a class template specialization
is also an explicit instantiation of the same kind (declaration or
definition) of each of its members (not including members inherited
from base classes) that has not been previously explicitly specialized
in the translation unit containing the explicit instantiation, except
as described below.
So if you had instead of an aggregate something akin to this:
template <typename>
struct X {
X();
};
template <typename T>
X<T>::X() {}
extern template struct X<int>;
int main()
{
X<int>{};
}
That would fail as you expect, since it ODR uses a constructor whose definition is never instantiated. The declaration is instantiated, because the enclosing specialization is instantiated, as mentioned above. But we never get any definition, under the suppressing effect of the explicit instantiation declaration.
Does this mean that the code snippet I posted is ill-formed, NDR?
Yes, by the exact sentence from [temp.explicit]/13 that you quoted. "An entity" means just that. It does not matter if an explicit instantiation declaration otherwise have no normative effect.
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
Consider next example :
#include <iostream>
template< int a >
void foo();
int main(int argn, char* argv[])
{
foo<1>();
}
template<>
void foo<1>()
{
std::cout<<1<<std::endl;
}
The compilation fails with next error messages :
rg.cpp:12: error: specialization of ‘void foo() [with int a = 1]’ after instantiation
What paragraph in the standard explains this error?
PS :I know that if I move the function definition in front of main will make the error go away.
I think that's undefined behavior according to the standard. There are no restrictions on what a toolchain can do in cases of UB, generating a compiler error is one of the friendlier possibilities.
Section [temp.spec], 14.7p5 says
For a given template and a given set of template-arguments,
an explicit instantiation definition shall appear at most once in a program,
an explicit specialization shall be defined at most once in a program (according to 3.2), and
both an explicit instantiation and a declaration of an explicit specialization shall not appear in a
program unless the explicit instantiation follows a declaration of the explicit specialization.
An implementation is not required to diagnose a violation of this rule.
Section [temp.expl.spec] 14.7.3p6 says:
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.
Your program violates these requirements.