`extern template` member functions - c++

I am working on a template function in a class:
class Data {
public:
template <typename T>
std::byte* serialize(const T& object) { /* serialize */ }
};
and I noticed that Data::serialize<Object> is instantiated in every compilation unit. For classes I could do, e.g.
extern template class Class<Object>;
in the header file and place
template class Class<Object>
to instantiate the Class<Object> only once and let the linker resolves the issue. Is there a way I do similar thing for functions and member functions?

It works exactly the same.
Explicit instantiation declaration in the header:
extern template std::byte* Data::serialize<Object>(const Object&);
And explicit instantiation definition in one translation unit:
template std::byte* Data::serialize<Object>(const Object&);
(<Object> is optional because it can be deduced from the const Object& parameter.)
However, consider that while this may reduce compilation time, it can also negatively affect compiler optimizations, because you make it harder to inline the function (at least without link-time optimization). The resulting binary will contain only one definition of the function template specialization anyway, whether you use explicit instantiation or not.

Related

Do templated ctor and methods need "inline" specifier if defined outside class? [duplicate]

Is it O.K. to define virtual function of class template outside its body? Virtual function can not be inlined, but to avoid multiple definitions in compilation units they shall be marked inline (assuming that template headers will be included in multiple source files). On the other hand compiler is free to ignore inline, so this seems valid. By an example, is the code below correct:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
?
BTW gcc (3.4.2) allows to omit inline before definition of function f(T val) but not before analogous function of regular class. Is it only gcc's behaviour?
Yes, it's OK even without inline. It works the same for ordinary member functions and static variables:
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
Standard quote: (3.2/5)
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements ...
The requirements basically say the two definitions have to be identical.
It doesn't work in case of regular classes. There has to be at most one definition in the whole program.
You can define template methods outside the class definition, in the same header, without using inline and without receiving multiple definition errors.
That's because a template function doesn't generate a definition itself, if it's not fully specialized. To prove my point, the following:
void C<int>::f(int)
{
}
will result in a linker error, as the function has a definition in this case. (provided you include this in multiple translation units. If you mark it inline:
inline void C<int>::f(int)
{
}
the error no longer occurs.
You can define the functions there, as long as any code which needs to instantiate the function in question has visibility of that code at compile time (not link time).
It's quite common to separate a template into 2 files, one being a traditional header, and the second being the implementation, as with non-templated functions and their implementation. The only difference is that you need to #include the template implementation file as well as the header when you want to use it.

Is it possible to add class template specialization and effect previous usages of this class?

I have some header file with declared template class and template function:
print.h:
template<typename T> struct Printer {
static void print();
};
template<typename T> void print();
In the implementation file, I have some base implementation of Printer, some specializations of it, and implementation of the function print that calls Printer<T>::print.
print.cpp
template<typename T> void Printer<T>::print() {
cout << "base";
}
template<> struct Printer<int> {
static void print() {
cout << "int";
}
};
template<> struct Printer<bool> {
static void print() {
cout << "bool";
}
};
template<typename T> void print() {
return Printer<T>::print();
}
In another file, I add one more specialization of Printer and a call of function print after it.
another.cpp
template<> struct Printer<char> {
static void print() {
cout << "char";
}
};
void printChar() {
print<char>();
}
Which Printer<T>::print does printChar call? Base or specialization Printer<char>? Can I change the behavior of printChar in this way?
(print.cpp is compiled first)
I compiled this code in a single file in the same order and called printChar. The output is 'char'. But I am not sure that it will work in different files as I described. Because for me it looks like it opens the ability to extend existing code by something like a cheating injection. But maybe it is OK to practice (Swift is based on a similar kind of extensions). If it works, Is it ok to practice it?
I'm not sure which previous usages you're referring to. I see only one usage of print<char>, after the specialization of print<char>.
Templates work kind of like #define, they stamp out definitions on-demand as needed. So the right template specialization definition had better be available at the time the code needs to be stamped out, which by the way takes place independently per TU. And these definitions must be identical across TU's.
See [temp.expl.spec]/pp.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 ... 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.
So as long as print<char> is instantiated after the specialization of print<char> in every translation unit where it is used (including implicit instantiations), the program is fine. The printChar() case is OK. But if print<char> happens to be instantiated in any other TU, the program would become ill-formed NDR.
For this reason all specializations are usually bundled (included) in the same header file that declares the primary template. It might increase compile times but can save a lot of headache during program development and maintenance later on.

Should I declare my function template specializations or is defining them enough?

I have some classes which can be checked. The code which implements this declares a function template in a header file and specializes it in different source files:
// check.h
template <class T>
bool check(const T& object);
// class1.h
struct Class1 {int mass;};
// check_class1.cpp
#include "class1.h"
#include "check.h"
template <>
bool check(const Class1& object) {return object.mass < 100;}
// class2.h
struct Class2 {int price;};
// check_class2.cpp
#include "class2.h"
#include "check.h"
template <>
bool check(const Class2& object) {return object.price < 1000;}
// class3.h
struct Class3 {int x;};
... // 10 more classes which I can check
This code is used like this:
#include "class1.h"
#include "class2.h"
#include "class3.h"
#include "check.h"
int main()
{
Class1 object1{50};
Class2 object2{500};
Class3 object3{8};
check(object1); // OK
check(object2); // OK
check(object3); // a link error appears here
}
This works pretty well. When I add another class Class3 which I can check, I don't need to touch the header file, because it defines a very wide interface. If I forgot to implement the check function for Class3, the linker will remind me with an error message.
My question is: is this behavior guaranteed, or does my code work by luck? I am using Visual Studio.
If I want to specialize my function template, shouldn't I declare all my specializations in the header file?
I'd add those declarations to be on the safe side (well, assuming I don't overload instead for whatever reason). I don't think the law is too clear on that. For one, we have
[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.
Which, if I read correctly, means that if an explicit specialization is added to main.cpp, then it must appear before main. Because that is where an implicit instantiation may occur. The paragraph doesn't make your code flat out ill-formed NDR, because the usage and the explicit specialization appear in different TU. But it does raise concerns.
On the other hand, there is this paragraph:
[temp]
7 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.
This one allows us to explicitly instantiate in separate unseen TU's. But it doesn't provide an allowance for explicit specializations. Whether or not that's intentional or an omission I cannot say.
The reason it works is likely due to how the whole thing is implemented. When the function declaration is implicitly instantiated it produces a symbol that just so happens to match the one produced by the explicit specialization. Matching symbols means a happy linker, so everything builds and runs.
But from a language-lawyer perspective, I think we can call the behavior here undefined by omission. It's undefined simply because the standard doesn't address it. So going back to my opening statement, I'd add them to be on the safe side, because at least then the placement is addressed by the standard.
You have to declare each explicit specialization before their use. But you can do that in the headers declaring the types for which it is specialized.
// class2.h
struct Class2 {int price;};
template <class T>
bool check(const T& object);
template <>
bool check(const Class2& object)
(I still don't understand why using overloads is not an option).

C++ - Define member function outside template-class but in header

I have defined a simple class-template with one member function. It is defined outside the class with an additional (explicit) specialization, also defined outside the class. All in one headerfile. If you include this header in multiple translation units you get a linker error due to One-Definition-Rule.
// Header with a template
template <class T>
class TestClass
{
public:
TestClass() {};
~TestClass() {};
bool MemberFunction();
};
template <class T>
bool TestClass<T>::MemberFunction()
{
return true;
}
template <>
bool TestClass<double>::MemberFunction()
{
return true;
};
Everything fine so far. But If I put the definition of the member function inside the class body, the linker error disappears and the functions can be used throughout different translation units.
// Header with a template
template <class T>
class TestClass
{
public:
TestClass() {};
~TestClass() {};
bool MemberFunction()
{
return true;
}
};
template <>
bool TestClass<double>::MemberFunction()
{
return true;
};
My question is why does it work that way? I use MSVC 2012. ODR has some exceptions on templates what I first thought to be the reason. But the definition of the "Base" function inside/outside the class makes the difference here.
14.7/5 says
5 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.
The second bullet applies to your case. The ODR defined in 3.2 says the same thing, albeit in a less distilled form.
Regardless of where and how the non-specialized version of member function is defined, the specialized version definition
template <> bool TestClass<double>::MemberFunction()
{
return true;
};
has to go into a .cpp file. If kept in the header file, it will produce an ODR violation once the header gets included into more than one translation unit. GCC reliably detect this violation. MSVC seems to be less reliable in that regard. But, as the quote above states, an implementation is not required to diagnose a violation of this rule.
The header file should only contain a non-defining declaration of that specialization
template <> bool TestClass<double>::MemberFunction();
The fact that in MSVC the error appears or disappears depending on such seemingly unrelated factor as how the non-specialized version of the function is defined must be a quirk of MSVC compiler.
After further research, it appears that MSVC implementation is actually broken: its behavior goes beyond what's allowed by the "no diagnostic is required" permission given by the language specification.
The behavior you observed in your experiments in consistent with the following: declaring the primary function template as inline automatically makes the explicit specialization of that template inline as well. This is not supposed to be that way. In 14.7.3/14 the language specification says
An explicit specialization of a function template is inline only if it
is declared with the inline specifier or defined as deleted, and
independently of whether its function template is inline.

Template definitions outside class body

Is it O.K. to define virtual function of class template outside its body? Virtual function can not be inlined, but to avoid multiple definitions in compilation units they shall be marked inline (assuming that template headers will be included in multiple source files). On the other hand compiler is free to ignore inline, so this seems valid. By an example, is the code below correct:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
?
BTW gcc (3.4.2) allows to omit inline before definition of function f(T val) but not before analogous function of regular class. Is it only gcc's behaviour?
Yes, it's OK even without inline. It works the same for ordinary member functions and static variables:
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
Standard quote: (3.2/5)
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements ...
The requirements basically say the two definitions have to be identical.
It doesn't work in case of regular classes. There has to be at most one definition in the whole program.
You can define template methods outside the class definition, in the same header, without using inline and without receiving multiple definition errors.
That's because a template function doesn't generate a definition itself, if it's not fully specialized. To prove my point, the following:
void C<int>::f(int)
{
}
will result in a linker error, as the function has a definition in this case. (provided you include this in multiple translation units. If you mark it inline:
inline void C<int>::f(int)
{
}
the error no longer occurs.
You can define the functions there, as long as any code which needs to instantiate the function in question has visibility of that code at compile time (not link time).
It's quite common to separate a template into 2 files, one being a traditional header, and the second being the implementation, as with non-templated functions and their implementation. The only difference is that you need to #include the template implementation file as well as the header when you want to use it.