No generated code for explicitly specialized template even with explicit instantiation - c++

I'm getting consistent behavior from both gcc 4.8.3 and clang 3.2, but do not understand why it is happening. Despite the fact that I have an explicit instantiation for a class template, the code is not being generated and I get an undefined symbol when I am using a fully specialized instance of the template.
I have a simple class template definition in a file 'temp.hpp'
#pragma once
template <typename T1>
class C
{
public:
C (T1 c) : d_c(c) {};
~C () = default;
void print ();
private:
T1 d_c;
};
Note that the method 'print()' is declared, but not defined here. I want the definition in the .cpp file and it will be specialized for different types.
So in the temp.cpp file I have the default definition of the print() method
#include "temp.hpp"
#include <iostream>
template<typename T1>
void
C<T1>::print ()
{
std::cout << "Printing: " << d_c << std::endl;
}
followed by a specialization of the class for the type 'float':
template <>
class C <float>
{
public:
C (float f) : d_f(f) {};
~C () = default;
void print ()
{
std::cout << "float: " << d_f << std::endl;
}
private:
float d_f;
};
and since the definitions are in the .cpp file I must explicitly instantiate all the specializations that I will be using. So I have:
template class C<int>;
template class C<float>;
The driver for my test looks like this in test.cpp:
#include "temp.hpp"
int main()
{
int i = 1;
C<int> c_int(i);
float f = 1.2;
C<float> c_float(f);
c_int.print();
c_float.print();
}
Upon compiling and linking this I get error:
test.cpp: undefined reference to `C<float>::print()'
The object code for the C< int > is properly generated. I can see it using nm:
nm -C temp.o
...
0000000000000000 W C<int>::print()
0000000000000000 W C<int>::C(int)
0000000000000000 W C<int>::C(int)
...
As I mentioned earlier, this is consistent with gcc and clang so I'm assuming there is some language rule I don't understand here.
Note that if I add a usage of the print() method in file temp.cpp, then the code is generated, but that is silly and in my real code would be impossible. For this simple test case it would look like:
void foo ()
{
C<float> s(1.3);
s.print();
}
In the real code which motivated this little test my template has 3 template arguments which combine to expand into about 30 permutations of the code. There are one or two of those for which I need a specialization which does something different, but the other 28 I can leave alone.
Any pointers on where I've gone wrong or a language reference for why the explicit instantiation of should not generate code are greatly appreciated. I've spent 1/2 a day reading all the other stackoverflow posts on explicit instantiation and believe I am using it correctly.

From [temp.expl.spec]:
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.
We're explicitly specializing C in temp.cpp, but in test.cpp, it is not declared before it is used. Thus, your code is ill-formed, no diagnostic required. You'll have to simply move the declaration of C<float> into temp.hpp
Always be careful with explicit specializations. The standard takes them very seriously:
The placement of explicit specialization declarations for function templates, class templates, [...], 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.

Related

Clang and Gcc disagree on explicit specialization after instantiation

In some code I am reviewing I ran into a case where Clang and Gcc disagree. After looking around awhile I cant seem to figure out who is right.
Disclaimer: I know there is a better Singleton pattern, but this is the one used in the code.
Notes:
gcc 7.4.0 on Ubuntu (No error)
clang 6.0.0 on Ubuntu (Throws error)
Difference appears to exist for all post C++11 ISO versions, but I did not try earlier.
foo.hh
#include "sing.hh"
class Foo {
public:
Foo();
~Foo();
static Foo *getSingleton(){
return singleton<Foo>::instance();
}
};
foo.cc
include "foo.hh"
//removing this line results in the error for clang disappearing
template<> singleton<Foo>::GetInstance singleton<Foo>::instance = nullptr;
int main(){};
sing.hh
template<typename T>
class singleton{
typedef T *(*GetInstance)(void);
public:
static GetInstance instance;
};
Results:
$ clang++ foo.cc
foo.cc:3:56: error: explicit specialization of 'instance' after instantiation
template<> singleton<Foo>::GetInstance singleton<Foo>::instance = nullptr;
^
./foo.hh:10:32: note: implicit instantiation first required here
return singleton<Foo>::instance();
^
1 error generated.
$ g++ foo.cc <- No Errors
Neither compiler is technically wrong. The code is invalid, but C++ implementations are not required to give a diagnostic message about this type of error.
Standard [temp.expl.spec]/6 says (emphasis mine):
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.
You can fix this by declaring the explicit specialization immediately after the definition of singleton in sing.hh:
struct Foo;
template<> singleton<Foo>::GetInstance singleton<Foo>::instance;
Or, if you want all specializations to initialize as null pointers, you can just define the member of the general class template, again probably in sing.hh. Then there's no need for explicit specializations, unless you want a different initializer for some certain type(s).
template<typename T>
typename singleton<T>::GetInstance singleton<T>::instance = nullptr;
From this answer here and the cpp-reference here.
Explicit specialization may be declared in any scope where its primary
template may be defined [...].
Explicit specialization has to appear after the non-specialized
template declaration.
Specialization must be declared before the first use that would cause
implicit instantiation, in every translation unit where such use
occurs
If the explicit specialization was in the sing.cpp file, then neither compiler would complain. Alternatively, you can use forward declaration to do the following and both clang and gcc would be happy.
#include <iostream>
template<typename T>
struct singleton
{
typedef T *(*GetInstance)(void);
static GetInstance instance;
};
template<>
singleton<struct Foo>::GetInstance singleton<struct Foo>::instance = nullptr;
struct Foo
{
static Foo *getSingleton()
{
return singleton<Foo>::instance();
}
};
int main()
{
}
Online code example: https://rextester.com/SPZLS83155

Checking whether a class template has been instantiated?

Is there an easy way to see whether a class has been instantiated in a translation unit? An exercise from C++ Primer asks for each labelled statement, whether an instantiation happens:
template <typename T> class Stack { };
void f1(Stack<char>); // (a)
class Exercise {
Stack<double> &rsd; // (b)
Stack<int> si; // (c)
};
int main() {
Stack<char> *sc; // (d)
f1(*sc); // (e)
int iObj = sizeof(Stack< string >); // (f)
}
I'm not sure how I could actually check my answers for these. I thought maybe I could use explicit instantiations for each class type (e.g. extern template class Stack<char>) and then never have a corresponding explicit instantiation definition in the program. That way if something was instantiated, if the definition didn't later appear then the linker would kick up an error.
However the compiler/linker doesn't always recognise such an error:
template <typename T> class A{ };
extern template class A<int>;
int main(){
A<int> a;
}
This compiles fine on gcc 4.9.2. However if this was the only object file in my program is should be an error as far as I can tell from [14.7.2][11] of N3337:
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 (14.7.1) 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.
(I'm guessing the "no diagnostic required" is why this doesn't kick up an error?). Alternatively is it the case that instantiations happen whenever an incomplete class type isn't viable for an expression - so that I could check by removing the definition of Stack?
template <typename T> class Stack;
So that each incomplete type error corresponds to a place where an instantiation would have occured?
You can use the nm tool on the executable. This will show what file contains function definitions. Also gcc provides a flag to strip out unused functions when doing the link.
Compile with “-fdata-sections” to keep the data in separate data sections and “-ffunction-sections” to keep functions in separate sections, so they (data and functions) can be discarded if unused.
Link with “–gc-sections” to remove unused sections.

gcc does not find template specialization

My network code uses template specialization to serialize types that can not simply be copied. I defined a general template
template<typename T> struct TypeHandler
that handles all types that can be transported by a simple memcpy and then I define specializations for all other types. The problem now is that I have a file with multiple such specializations and if I compile the code with Visual Studio everything works fine. But with gcc all template specializations in that file get used with the exception of
template<> struct TypeHandler<uint32_t>
which variable length encodes the integer to save space.
Namespaces are the same for all TypeHandler versions and they are even in the same file. But for some reason gcc decides to use the generalized version and I don't really know why.
EDIT:
It seems that gcc uses the instantiation of TypeHandler from an other project that this one links against but doesnt have a specialization for uint32_t even so it transmits uint32_t fields. GCC doesnt give me any error though. How can i tell gcc to use the specialization like Visual Studio does ?
EDIT2:
managed to generate an SSCCE http://netload.in/dateiz3R4eTVqi3/src.tar.gz.htm
the bug here is the other way around but well.
EDIT3:
fixed filesize : http://netload.in/dateixP6iOvc6bD/src.zip.htm
Minimized to:
test1.cpp:
#include <iostream>
#include <stdint.h>
template<typename T>
struct TypeHandler
{
void Print() { std::cout << "base" << std::endl; }
};
void test1()
{
std::cout << "p1" << std::endl;
TypeHandler<uint32_t>().Print();
}
test2.cpp:
#include <iostream>
#include <stdint.h>
template<typename T>
struct TypeHandler
{
void Print() { std::cout << "base" << std::endl; }
};
template<>
struct TypeHandler<uint32_t>
{
void Print() { std::cout << "int" << std::endl; }
};
void test2()
{
std::cout << "p2" << std::endl;
TypeHandler<uint32_t>().Print();
}
main.cpp:
void test1();
void test2();
int main(){
test1();
test2();
}
On Windows/MinGW 4.8.2, compiling with g++ test1.cpp test2.cpp main.cpp -o test and running produces
p1
base
p2
base
while using g++ test2.cpp test1.cpp main.cpp -o test produces
p1
int
p2
int
This is a straightforward standard violation causing undefined behavior. You can't explicitly specialize the same template in one translation unit but not the other. The explicit specialization is not visible in test1.cpp, causing the compiler to generate an implicit instantiation from the base template. So you get two TypeHandler<uint32_t> specializations, and in this instance it appears that the linker decided to pick the one from the first object file it saw. From §14.7.3 [temp.expl.spec]/p6 of the standard (emphasis mine):
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.
Also, obligatory quote of the next paragraph (emphasis mine):
The placement of explicit specialization declarations for function
templates, class 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, member functions of member templates of class templates,
member functions of 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,
member class 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.

Why full specialization of template function is not picked up from the .cpp file without declaration?

Following code generate no compilation/linker error/warning:
// A.h
#include<iostream>
struct A
{
template<typename T>
static void foo (T t)
{
std::cout << "A::foo(T)\n";
}
};
void other ();
// main.cpp
#include"A.h"
int main ()
{
A::foo(4.7);
other();
}
// other.cpp
#include"A.h"
template<>
void A::foo (double d)
{
cout << "A::foo(double)\n";
}
int other ()
{
A::foo(4.7);
}
The output surprisingly is:
A::foo(T)
A::foo(double)
Why compiler is not able to pick up the correct A::foo(double) in case of main.cpp ?
Agree that, there is no issue as expected, if there is a declaration in A.h like below:
template<> void A::foo (double);
But that's not the concern, because at link time, compiler has the specialized version.
Also, is having 2 different version of the same function an Undefined Behavior ?
All explicit specialization declarations must be visible at the time of the template instantiation. Since your explicit specialization declaration for A::foo<double> is visible in one translation unit but not the other, the program is ill-formed.
(In practice, the compiler will instantiate the primary template in main.cpp and the explicitly-specialized one in other.cpp. That would still an ODR violation anyway.)
main.cpp cannot see the code inside other.cpp. Template specializations are of file scope.
Why compiler is not able to pick up the correct A::foo(double) in case of main.cpp ?
The problem is that in a separate compilation model without a declaration available in the header the compiler wouldn't possibly know whether an specialization exists in any translation unit that will later be linked or whether it needs to instantiate the template. The decision in the language is that the absence of a declaration means that there is no manual specialization of the template, and thus the compiler needs to generate one now.
is having 2 different version of the same function an Undefined Behavior ?
Yes it is. Whether one of the specializations was automatically generated or not, the fact is that it is undefined behavior as it is a violation of the One Definition Rule (there are multiple definitions of the same symbol).

Template instantiation details of GCC and MS compilers

Could anyone provide a comparison or specific details of how is template instantiation
handled at compile and/or link time in GCC and MS compilers? Is this process different
in the context of static libraries, shared libraries and executables?
I found this doc about how GCC handles it but I'm not sure if the information
is still referring to the current state of things. Should I use the flags
they suggest there when compiling my libraries e.g. -fno-implicit-templates?
What I know (might not necessarily be correct) is that:
templates will be instantiated when actually used
templates will be instantiated as a result of explicit instantiations
duplicate instantiation is usually handled by folding duplicate instantiations, or by deferring instantiation until link time
Point of instantiation
templates will be instantiated when actually used
Not exactly, but roughly. The precise point of instantiation is a bit subtle, and I delegate you over to the section named Point of instantiation in Vandevoorde's/Josuttis' fine book.
However, compilers do not necessarily implement the POIs correctly: Bug c++/41995: Incorrect point of instantiation for function template
Partial instantiation
templates will be instantiated when actually used
That is partially correct. It is true for function templates, but for class templates, only the member functions that are used are instantiated. The following is well-formed code:
#include <iostream>
template <typename> struct Foo {
void let_me_stay() {
this->is->valid->code. get->off->my->lawn;
}
void fun() { std::cout << "fun()" << std::endl; }
};
int main () {
Foo<void> foo;
foo.fun();
}
let_me_stay() is checked syntactically (and the syntax there is correct), but not semantically (i.e. it is not interpreted).
Two phase lookup
However, only dependent code is interpreted later; clearly, within Foo<>, this is dependent upon the exact template-id with which Foo<> is instantiated, so we postponed error-checking of Foo<>::let_me_alone() until instantiation time.
But if we do not use something that depends on the specific instantiation, the code must be good. Therefore, the following is not well-formed:
$ cat non-dependent.cc
template <typename> struct Foo {
void I_wont_compile() { Mine->is->valid->code. get->off->my->lawn; }
};
int main () {} // note: no single instantiation
Mine is a completely unknown symbol to the compiler, unlike this, for which the compiler could determine it's instance dependency.
The key-point here is that C++ uses a model of two-phase-lookup, where it does checking for non-dependent code in the first phase, and semantic checking for dependent code is done in phase two (and instantiation time) (this is also an often misunderstood or unknown concept, many C++ programmers assume that templates are not parsed at all until instantiation, but that's only myth coming from, ..., Microsoft C++).
Full instantiation of class templates
The definition of Foo<>::let_me_stay() worked because error checking was postponed to later, as for the this pointer, which is dependent. Except when you would have made use of
explicit instantiations
cat > foo.cc
#include <iostream>
template <typename> struct Foo {
void let_me_stay() { this->is->valid->code. get->off->my->lawn; }
void fun() { std::cout << "fun()" << std::endl; }
};
template struct Foo<void>;
int main () {
Foo<void> foo;
foo.fun();
}
g++ foo.cc
error: error: ‘struct Foo<void>’ has no member named ‘is’
Template definitions in different units of translation
When you explicitly instantiate, you instantiate explicitly. And make all symbols visible to the linker, which also means that the template definition may reside in different units of translation:
$ cat A.cc
template <typename> struct Foo {
void fun(); // Note: no definition
};
int main () {
Foo<void>().fun();
}
$ cat B.cc
#include <iostream>
template <typename> struct Foo {
void fun();
};
template <typename T>
void Foo<T>::fun() {
std::cout << "fun!" << std::endl;
} // Note: definition with extern linkage
template struct Foo<void>; // explicit instantiation upon void
$ g++ A.cc B.cc
$ ./a.out
fun!
However, you must explicitly instantiate for all template arguments to be used, otherwise
$ cat A.cc
template <typename> struct Foo {
void fun(); // Note: no definition
};
int main () {
Foo<float>().fun();
}
$ g++ A.cc B.cc
undefined reference to `Foo<float>::fun()'
Small note about two-phase lookup: Whether a compiler actually implements two-phase lookup is not dictated by the standard. To be conformant, however, it should work as if it did (just like addition or multiplication do not necessarily have to be performed using addition or multiplication CPU instructions.
Edit: It turns out that what I wrote below is contrary to the C++ standard. It is true for Visual C++, but false for compilers that use "two-phase name lookup".
As far as I know, what you say is correct. Templates will be instantiated when actually used (including when declared as a member of another type, but not when mentioned in a function declaration (that does not have a body)) or as a result of explicit instantiations.
A problem with templates is that if you use the same template (e.g. vector) in several different compilation units (.cpp files), the compiler repeats the work of instantiating the template in each .cpp file, thus slowing down compilation. IIRC, GCC has some (non-standard?) mechanism that can be used to avoid this (but I don't use GCC). But Visual C++ always repeats this work, unless you use explicit template instantiation in a precompiled header (but even this will slow down your compile, since a larger PCH file takes longer to load.) Afterward, the linker then eliminates the duplicates. Note: a comment below linked to a page which tells us that not all compilers operate this way. Some compilers defer function instantiation until link time, which should be more efficient.
A template is not fully instantiated when it is first used. In particular, functions in the template are not instantiated until they are actually called. You can easily verify this by adding a nonsense function to a template you are actively using:
void Test() { fdsh "s.w" = 6; wtf? }
You won't get an error unless you instantiate the template explicitly, or try to call the function.
I expect static libraries (and object files) will store the object code of all templates that were instantiated. But if your program has a certain static library as a dependency, you can't actually call the template functions that were already instantiated therein, at least not in VC++, which always requires the source code (with function bodies) of a template class in order to call functions in it.
I don't think it's possible to call a template function in a shared library (when you don't have the source code of the template function you want to call).