(I am sorry for the messy title. I will gladly accept suggestions to improve it.)
I will try to be as straightforward as possible. I have the folowing code:
file1.hpp
template <class val_t>
struct MatOps;
file2.hpp:
#include "file1.hpp"
template <> struct MatOps<float>{
static void method1(){
// Do something
}
static void method2(){
// Do something
}
static void method3(){
// Do something
}
}
File3.hpp:
#include "file1.hpp"
template <> struct MatOps<double>{
static void method1(){
// Do something different
}
static void method2(){
// Do something different
}
static void method3(){
// Do something different
}
}
main.cpp
#include "file2.hpp"
#include "file3.hpp"
int main(){
float a,b,c,d;
MatOps<float>::method1(a,b,...);
MatOps<float>::method2(c,d,...);
return 0;
}
Questions:
I am not using the explicit specialization MatOps<double>. However, is MatOps<double> actually instantiated? Or more roughly: does the inclusion of file3.hpp occupy any storage whatsoever?
I am not using MatOps<float>::method3(), but I am using the other methods in the class. Since I am explicitely using MatOps<float>, does the compiler generate code for MatOps<float>::method3()?
Rationale: I have been asked to follow some guidelines in the MISRA C++:2003 standard. Although obsolete, I have been encouraged to use whatever is reasonable in there. In particular, there is a rule that reads:
Header files should be used to declare objects, functinos, inline functions, function templates, typedefs, macros, classes, and class templates and shall not contain or produce definitions of objects or functions (or fragments of functions or objects) that occupy storage.
A header file is considered to be any file that is included via the #include directive, regardless of name or suffix.
My code is heavily templated and hence I can include any files according to this rule. My problem comes when I do full specializations (I only do two of them: the ones listed in file2.hpp and file3.hpp). What are full template specializations? Is code generated for them even if they are not used? Ultimately, do they occupy storage?
To answer your first question, I quote the following from cppreference.com:
A class template by itself is not a type, or an object, or any other
entity. No code is generated from a source file that contains only
template definitions. In order for any code to appear, a template must
be instantiated: the template arguments must be provided so that the
compiler can generate an actual class (or function, from a function
template).
Inclusion of file3.hpp will not result in code generation by itself.
As for the second part, again from the same page,
When code refers to a template in context that requires a completely
defined type, or when the completeness of the type affects the code,
and this particular type has not been explicitly instantiated,
implicit instantiation occurs. For example, when an object of this
type is constructed, but not when a pointer to this type is
constructed.
This applies to the members of the class template: unless the member is
used in the program, it is not instantiated, and does not
require a definition.
Unless you are doing an explicit instantiation of your class template, individual member functions of your class template will not get instantiated, i.e., the compiler will not generate code for MatOps<float>::method3().
Related
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).
Suppose I am attempting to create my own implementation of boost::filesystem::path, using the Curiously Recurring Template Pattern:
(Code is given incomplete for brevity, but will exhibit the problem as stated when compiled with 'g++ -std=c++11 -o mypath ./mypath.cpp', using GCC 4.8.4)
mypath.hpp:
#ifndef MYPATH_HPP
#define MYPATH_HPP
#include <string>
#include <vector>
namespace my {
template <class T>
class PathBase
{
public:
PathBase();
PathBase(std::string const& p);
std::string String() const;
bool IsSeparator(char c) const;
std::string Separators() const;
typedef std::vector<std::string> pathvec;
protected:
pathvec _path;
private:
virtual std::string _separators() const =0;
};
class Path : public PathBase<Path>
{
public:
Path();
Path(std::string const& p);
private:
virtual std::string _separators() const final;
};
} // namespace 'my'
#endif // MYPATH_HPP
mypath.cpp:
#include "mypath.hpp"
namespace my {
//////////template class PathBase<Path>;
template<>
bool PathBase<Path>::IsSeparator(char c) const
{
return (Separators().find(c) != std::string::npos);
}
template <>
std::string PathBase<Path>::Separators() const
{
return _separators();
}
} // namespace
int main(int argc, char** argv)
{
return 0;
}
Of course I discovered that the code as-written will not compile, since I explicitly specialize Separators() after IsSeparator() has implicitly instantiated it. But I don't particularly want to play whack-a-mole trying to keep all my methods favorably ordered.
While researching similar questions on SO, I found that this accepted answer to one of them suggested that I could solve this problem neatly by merely declaring my specialization. But...
My commented-out template class PathBase<Path>; line in mypath.cpp had no effect on the problem, and
It kinda feels like my header file already declares the explicit specialization with its entire class Path : public PathBase<Path> { ... } declaration.
Exactly what does my explicit declaration need to look like?
Let's get these out of the way first:
template class PathBase<Path>; does not declare an explicit specialization; it is an explicit instantiation definition. You're requesting that the compiler instantiate PathBase<Path> and all its members for which it has definitions, based on the definitions you provided up to that point. In this specific case, it doesn't make any difference indeed.
The declaration of an explicit specialization would look like template<> class PathBase<Path>;, but that's not what you want here either; see below.
The use of PathBase<Path> when defining Path doesn't declare an explicit specialization either; it triggers an implicit instantiation of PathBase<Path>, based on the definition you provided above. An implicit instantiation for a class template instantiates the class definition and only the declarations of its member functions; it doesn't try to instantiate the definitions of the functions; those are only instantiated when needed, later on.
In your cpp file, you're explicitly specializing IsSeparator and Separators for an implicitly instantiated PathBase<Path>. You're requesting that the compiler instantiate PathBase<Path> based on the generic definition you provided, but, when the definitions of those particular functions are needed, use the specific definitions you provide.
It's basically a shorthand alternative to explicitly specializing the whole class template, when the structure of the class and most of the generic definitions for the members are fine, and you only want to fine-tune the definitions of a few members. If you explicitly specialized the whole class template, you'd have to provide a separate class definition and definitions for all the member functions of the specialization, which would mean unnecessary copy-paste.
You need to tell the compiler about those explicit specializations as soon as possible, before there's any chance that some code would attempt to use the definitions (it needs to know that it will have to look for specific definitions instead of generic ones). You do that by declaring (not necessarily defining) the explicit specializations.
The safest place to do that is immediately after the closing brace of the definition of template <class T> class PathBase. Something like:
class Path;
template<> std::string PathBase<Path>::Separators() const;
template<> bool PathBase<Path>::IsSeparator(char c) const;
You definitely need to do this in the header file, not in a cpp file, otherwise other cpp files that use the header will not know about the explicit specializations and will try to instantiate generic versions (if they need them). That will make your program ill-formed, no diagnostic required (this applies to your example as well). What that means is: if the compiler is smart enough to diagnose the problem, you should be grateful; if it isn't, you can't complain, and it's still your fault.
Having declared the explicit specializations up front, the definitions can come later, possibly in a separate cpp file; that's fine, just like for normal functions.
Also note that, should you want to include the definitions for the explicit specializations in the header file (to ease inlining, for example), you'll have to declare them inline, again like for normal functions. Otherwise, including the header in multiple cpp files will make the program ill-formed, NDR (you'll typically get multiple definition errors at link time).
Obligatory standard quote from [temp.expl.spec]/7:
[...] 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.
Yes, the members of the standardization committee are human too.
consider the following code:
//header.h
template<class T>
class A
{
static int x;
};
template<class T>
int A<T>::x = 0;
//source1.cpp
#include "header.h"
void f(){} // dummy function
//main.cpp
#include "header.h"
int main(){}
In this case code compiles perfectly without errors, but if I remove the template qualifier from class
class A
{
static int x;
};
int A::x = 0;
In this case compiler erred with multiple definition of x. Can anybody explain this behavior?
And when the template class's static variable is initialized / instantiated??
Compiler will remove duplicate template instantiations on its own. If you turn your template class into regular one, then its your duty to make sure only one definition of static variable exists (otherwise linker error will appear). Also remember that static data members are not shared between instatiations of templates for different types. With c++11 you can control instatiations on your own using extern templates: using extern template (C++11).
As for the point of instatiation for static members:
14.6.4.1 Point of instantiation [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.
so point of instatiation should be ie. right after main() if you use your type for the first time inside main().
Templates as the name suggest are the the fragments of code that will be used several times for different parameters. For templates the compiler is to ensure if their methods and static fiels definition are linked only ones. So if you create a static field with its default value the compiler is obliged to provide single memory cell (for the same template parameter set) even though the template class header is included several times. Unfortunetly non-template classes you need to be managed by yourself.
As for the second question, I believe the standard does not state when the static fields need to be initialized, each compiler can implement then it in its own manner.
It is necessary to instantiate/initialize static members in cpp files not in headers. Static members are property of class not property of objects, so if you include header file in more cpp files, it looks like you are initializing it more times.
Answer to this question is more complex. Template is not one class. It is instantiating on demand. It means that every different use of template is one standalone "template instance". For example if you use A<int> and A<float> than you will have 2 different classes therefore you would need to initialize A<int>::x and A<float>::x.
For more info see this answer: https://stackoverflow.com/a/607335/1280316
A class (be it a template or not) can (and should) be declared in any compilation unit that referes to it.
A static field initialization does defines a variable, and as such it should exist only in one compilation unit -> that's the reason why you get an error when class A is not a template.
But when you declare a template, nothing is really created untill you instantiate it. As you never instantiate the template, the static field is never defined and you get no error.
If you had two different instantiations in source1.cpp (say A<B>) and main.cpp (say A<C>) all will still be fine : you would get A<B>::x in source1 and A<C>::x in main => two different variables since A<B> and A<C> are different classes.
The case where you instantiate same class in different compilation units is trickier. It should generate an error, but if it did, you could hardly declare special fields in templates. So it is processed as a special case by the compiler as it is explained in this other answer to generate no errors.
I understand that template definitions should be put in the header file. Does this mean that all the definitions of the classes that the template uses (directly or indirectly) need to be put in the header files as well?
I have a template that has a lot of classes it depends on and thus have to put them all in the header file otherwise I will get "error LNK2019: unresolved external symbol ". Is there a better solution in terms of code organisation?
Example:
double inline MainFunction(double price, const Params& params)
{
Price<ModeEnum::NORMAL> pricer(price);
MethodOne<ModeEnum::NORMAL> methodOne;
return pricer.func(methodOne, params) ;
}
template<ModelEnum::Enum Mode>
struct Price
{
double price;
typedef double return_type;
Price(double price_) : price(price_){}
template<typename T> double func(const T& method, const Params& params) const
{
const typename T::PriceFactor factor(params);
return factor ..... ;
}
};
T::PriceFactor is actually class B that is a type definition defined in the tempalte MethodOne. Because of this, I have to put the constructor of class B and all (a lot) the functions and class that it uses in the header file.
The simple answer is this: all code needs to be visible to the compiler when the template gets instantiated. If the code isn't visible, the compiler won't do the instantiation and you'll need to provide an explicit instantiation. Whether an explicit instantiation is viable, depends on the nature of your template:
Templates which are applicable to many types, e.g., something like std::vector<T> probably want to be implemented entirely in a header. You may separate the declaration and the definition of function templates but there isn't much point in putting the parts into different files.
Templates which are applicable to few types, e.g., std::basic_ostream<cT> which is instantiated with char, wchar_t and maybe at some point with char16_t and char32_t probably want to be declared in a header and defined in another header which is not included automatically. Instead the header with the definitions is included only in special instantiation files where the class templates are explicitly instantiated.
Some templates give classes with different properties the same interface. That used to be the case with std::complex<T> which could be instantiated with float, double, and long double. For templates like these the header would only include the declarations and the definitions would go into a suitable translation unit.
One theme which is orthogonal to the above discussion is factoring out common parts, ideally into non-templates are into templates with fewer instantiations: it may very well be possible to take a very general interface but implement it in terms of a much more restrictive interface at the cost of somehow bridging the gap as part of the template implementation. In that case the "interesting" implementation may go into a source file rather than a header and the templates in the interface just adapt the passed in types to the actual implementation.
When mentioning above that code would be place into a source file this, obviously only applies to non-trivial code: simple forwarding functions probably should stay inline functions for performance reasons. However, these tend not to be the interesting function templates causing lots of dependencies.
For a more complete write-up on how to organize template code see this blog entry.
If its simple, I just put it all in one header:
//simple_template.h
#ifndef SIMPLE_TEMPLATE_H
#define SIMPLE_TEMPLATE_H
template <typename T>
class SomethingSimple
{
public:
T foo() { return T();}
};
#endif
If it is more complicated, I create an "inline header" (and use the naming convention from the google style guide) to get:
//complicated_template.h
#ifndef COMPLICATED_TEMPLATE_H
#define COMPLICATED_TEMPLATE_H
template <typename T>
class SomethingComplicated
{
public:
T foo();
};
#include "compilcated_template-inl.h"
#endif
//compilcated_template-inl.h
#ifndef COMPLICATED_TEMPLATE_INL_H
#define COMPLICATED_TEMPLATE_INL_H
#include "complicated_template.h"
template <typename T>
T SomethingComplicated<T>::foo() {/*lots of code here*/; return T();}
#endif
This way, complicated_template.h is pretty readable, but anyone who uses the template can just include that header. For example,
//uses_template.h
#ifndef USES_TEMPLATE_H
#define USES_TEMPLATE_H
#include "complicated_template.h"
class something_using_complicated
{
private:
SomethingComplicated<int> something_;
};
Note: if the classes that use the template are also template classes then you're stuck with a header only library. This is why BOOST is mostly headers.
Always considering that the following header, containing my templated class, is included in at least two .CPP files, this code compiles correctly:
template <class T>
class TClass
{
public:
void doSomething(std::vector<T> * v);
};
template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
// Do something with a vector of a generic T
}
template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
// Do something with a vector of int's
}
But note the inline in the specialization method. It is required to avoid a linker error (in VS2008 is LNK2005) due to the method being defined more then once. I understand this because AFAIK a full template specialization is the same as a simple method definition.
So, how do I remove that inline? The code should not be duplicated in every use of it. I've searched Google, read some questions here in SO and tried many of the suggested solutions but none successfully built (at least not in VS 2008).
Thanks!
As with simple functions you can use declaration and implementation.
Put in your header declaration:
template <>
void TClass<int>::doSomething(std::vector<int> * v);
and put implementation into one of your cpp-files:
template <>
void TClass<int>::doSomething(std::vector<int> * v) {
// Do somtehing with a vector of int's
}
Don't forget to remove inline (I forgot and thought this solution will not work :) ).
Checked on VC++2005
You need to move specialization definition to CPP file.
Specialization of member function of template class is allowed even if function is not declared as template.
There is no reason to remove the keyword inline.
It does not change the meaning of the code in anyway.
If you want to remove the inline for whatever reason the solution of maxim1000 is perfectly valid.
In your comment, though, it seems you believe that the inline keyword means that the function with all his contents gets always inlined but AFAIK that is actually very much dependent on your compiler optimization.
Quoting from the C++ FAQ
There are several ways to designate that a function is inline, some of
which involve the inline keyword, others do not. No matter how you
designate a function as inline, it is a request that the compiler is
allowed to ignore: the compiler might inline-expand some, all, or none
of the places where you call a function designated as inline. (Don’t
get discouraged if that seems hopelessly vague. The flexibility of the
above is actually a huge advantage: it lets the compiler treat large
functions differently from small ones, plus it lets the compiler
generate code that is easy to debug if you select the right compiler
options.)
So, unless you know that that function will actually bloat your executable or unless you want to remove it from the template definition header for other reasons, you can actually leave it where it is without any harm
This is a little OT, but I thought I'd leave this here in case it helps someone else. I was googling about template specialization which led me here, and while #maxim1000's answer is correct and ultimately helped me figure my problems out, I didn't think it was abundantly clear.
My situation is a little different (but similar enough to leave this answer I think) than the OP's. Basically, I'm using a third party library with all different kinds of classes that define "status types". The heart of these types are simply enums, but the classes all inherit from a common (abstract) parent and provide different utility functions, such as operator overloading and a static toString(enum type) function. Each status enum is different from one another and unrelated. For example, one enum has the fields NORMAL, DEGRADED, INOPERABLE, another has AVAILBLE, PENDING, MISSING, etc. My software is in charge of managing different types of statuses for different components. It came about that I wanted to utilize the toString functions for these enum classes, but since they're abstract I couldn't instantiate them directly. I could have extended each class I wanted to use, but ultimately I decided to create a template class, where the typename would be whatever concrete status enum I cared about. Probably some debate can be had about that decision, but I felt like that was a lot less work than extending each abstract enum class with a custom one of my own and implementing the abstract functions. And of course in my code, I just wanted to be able to call .toString(enum type) and have it print the string representation of that enum. Since all the enums were entirely unrelated, they each had their own toString functions that (after some research I learned) had to be called using template specialization. That led me here. Below is an MCVE of what I had to do in order to make this work correctly. And actually my solution was a bit different than #maxim1000's.
This is a (greatly simplified) header file for the enums. In reality, each enum class was defined in it's own file. This file represents the header files that are supplied to me as part of the library I am using:
// file enums.h
#include <string>
class Enum1
{
public:
enum EnumerationItem
{
BEARS1,
BEARS2,
BEARS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
class Enum2
{
public:
enum EnumerationItem
{
TIGERS1,
TIGERS2,
TIGERS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
adding this line just to separate the next file into a different code block:
// file TemplateExample.h
#include <string>
template <typename T>
class TemplateExample
{
public:
TemplateExample(T t);
virtual ~TemplateExample();
// this is the function I was most concerned about. Unlike #maxim1000's
// answer where (s)he declared it outside the class with full template
// parameters, I was able to keep mine declared in the class just like
// this
std::string toString();
private:
T type_;
};
template <typename T>
TemplateExample<T>::TemplateExample(T t)
: type_(t)
{
}
template <typename T>
TemplateExample<T>::~TemplateExample()
{
}
next file
// file TemplateExample.cpp
#include <string>
#include "enums.h"
#include "TemplateExample.h"
// for each enum type, I specify a different toString method, and the
// correct one gets called when I call it on that type.
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
return Enum1::toString(type_);
}
template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
return Enum2::toString(type_);
}
next file
// and finally, main.cpp
#include <iostream>
#include "TemplateExample.h"
#include "enums.h"
int main()
{
TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1);
TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3);
std::cout << t1.toString() << std::endl;
std::cout << t2.toString() << std::endl;
return 0;
}
and this outputs:
BEARS1
TIGERS3
No clue if this is the ideal solution to solve my problem, but it worked for me. Now, no matter how many enumeration types I end up using, all I have to do is add a few lines for the toString method in the .cpp file, and I can use the libraries already-defined toString method without implementing it myself and without extending each enum class I want to use.
I'd like to add that there is still a good reason to keep the inline keyword there if you intend to leave also the specialization in the header file.
"Intuitively, when you fully specialize something, it doesn't depend on a template parameter any more -- so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule..."
Reference: https://stackoverflow.com/a/4445772/1294184