How to create a template instantiation for an abstract baseclass? - c++

I have an abstract class Primitive, which has some pure abstract functions.
Then i have a tree implementation with templates:
template<typename PrimitiveT>
class PrimitiveTree {
...
}
// explicit instantiation
template class PrimitiveTree<Project::Primitive>; // abstract
template class PrimitiveTree<SimpleTrianglePrimitive>; // implementation
which is used in another file as
PrimitiveTree<Primitive> *ptree;
With this code I get error C2259: 'Project::Primitive': cannot instantiate abstract class. When I remove the instantiation of the abstract class, I get linker errors that the corresponding symbol for PrimitiveTree<Primitive> is not found in the object file.
A similiar class with the methods inside the header file doesn't have these problems, when used with Primitive as template argument.
How do i need to instantiate the template class, such that the neccessary symbols are added to the object file, even when the template argument is an abstract class?

You need to ensure that the template PrimitiveTree<PrimitiveT> does not rely on PrimitiveT (the template parameter) being instantiable - in other words, not being abstract. One property of an abstract class is that it cannot be instantiated.
This means your PrimitiveTree template must only work with pointers or references to PrimitiveT, and never instantiate an actual instance PrimitiveT in any way. This means it is not possible to declare PrimitiveT as a data member (static or non-static). It is not possible to pass a PrimitiveT by value. It is also not possible dynamically create any instances with a new expression (e.g. some_pointer = new PrimitiveT[5]) since a new expression relies on the type being instantiable (i.e. not abstract).
Everywhere where PrimitiveT is used must be either a reference or a pointer. Defining or declaring a pointer or reference to PrimitiveT, or passing a reference/pointer as a function argument does not rely on PrimitiveT being instantiable.
If you write ANY code for PrimitiveTree that relies on PrimitiveT being instantiated, then the implementation cannot instantiate the template.
The "similar class" in another header file probably does not rely on Primitive being instantiable, since it follows guidelines like the above.

Related

Is it possible to define a non-template function that can take a templated object as a parameter

I am using a C++ class which is templated.
I instantiate two different templated version of this class:
ExampleClass<ParamType1> obj1;
ExampleClass<ParamType2> obj2;
So that I have two objects which are the same class, but with different template parameters.
I now want to be able to define a function (extremely simplified example!) that can take either obj1 or obj2 as a parameter:
int func(ExampleClassXXX obj_param)
{
return obj_param.member_operation();
}
So that I can call either func(obj1) or func(obj2.
Is this something that is possible, and if so, what is the syntax needed for the function definition to specify the obj_param parameter is "an instance of ExampleClass created with any template parameters"?
The answer to this question sort of covers the case that is one step more general - having "obj_param" be any type. Most of the details are missing from the text of that answer, it is only when you click on the "live demo" that you see they are instantiating a templated struct to be able to pass in the generic parameter, which is pretty ugly.
It seems like this should be a common thing to want to do, but Googling has failed me so far (searching for "passing templated object as function parameter")
Note that
ExampleClass<ParamType1>
and
ExampleClass<ParamType2>
are basically two different classes for the language.
You have two possibilities, in my opinion, the first being:
template<typename ParamType>
int func(ExampleClass<ParamType> obj_param){}
The second possibility is to give to ExampleClass a non-templated public base class (basically implementing type erasure) like so
template<typename T>
class ExampleClass : public ExampleClassBase{};
and then re-write the function as
int func(ExampleClassBase& obj_param){}
but you will not be able to pass by value in this case because of object slicing issues.
The template function forces you to implement the function in a header file if you want to keep it as general as possible, the non-templated base class forces you to pay for virtual function call.
Edit: as per Alan Birtles comment, if you know already all the types you will instantiate ExampleClass with you can implement each version of the function in a cpp file.
So that I have two objects which are the same class, but with different template parameters.
A contradiction right there. If the arguments are different, this is not the same class. A template is not a class, it's a mold. If you pour two different metals into it, you'd get two very different objects, despite the similar shape. They'd have different mass and density, possibly different electromagnetic properties, and so forth. A bit tangential, but it's important to differentiate the template from the things it produces, those are not the same.
This is why different specializations produced from the same template are considered different classes. They are not related under the type system, and so no function can automatically treat them as the same thing. You could create a function template, and use it to generate functions for each distinct specialization, but those too would be different functions.
If you have a part that's common to all specializations, you could refactor it out into a base class (proper class, not a class template), and have a function that accepts that.

Pure constructors in class templates

I have some code that works, and I'm not sure why. I'm instantiating a class as an immutable variable. There are no immutable constructors in the class and none are labeled as pure, but it just works anyway.
I also read that pure constructors can be used across the board for mutable, immutable, const, and shared instances
The only thing I can find on the D website is that purity is inferred in function templates. Should I assume that since my class is parameterized (or a class template) that the compiler is inferring the purity of all the methods, including the constructor?
Code below:
public class Data(size_t numInputs, size_t numTargets)
{
...
public this(in double[][] data, in bool[] filter, in bool doNorm = true)
{
...
}
}
The only thing I can find on the D website is that purity is inferred in function templates. Should I assume that since my class is parameterized (or a class template) that the compiler is inferring the purity of all the methods, including the constructor?
Yes. Since the class is a template, all the methods are also templates (consider that they have to be since the hidden this parameter's type comes from the template). Thus, their body must be available in the source. The two requirements for inferred attributes are body source available and a template parameter for them (and also the function must not try to call or inspect itself, but you don't do that either) thus it can be inferred as pure.

(Can I minimize the) Footprint of template in my C++ Code?

I have a large class which basically handles one buffer of variable (numeric) datatype. So it seems a good choice to use a class template with this datatype as the only parameter. I'm not experienced in C++ and I wonder/worry a bit about the "footprint" such a template makes in my code.
There are three implications of templates which in my (C++ unexperienced) eyes are not necessary and make code ugly. I tried to avoid them, but neither did I find a good example how to do it nor did I manage to find it out by myself.
So the goal of this question is: Can you either confirm the following statements or give a counterexample?
When using a class template, all class methods have to go into the header file. Even if they have no templated type in their interface or implementation.
When using a static method or member of the class, I always have to specify a template parameter (MyClass< double > :: MY_STATIC), even if the templatization does not affect any of the static properties of the class.
When using the class as a parameter for a function, I always have to give a template parameter, even when this function does not access any of the templated members? (function myFunc(MyClass< double> & myClass){ do something } )
As a general rule, don't have functions/data members in a template class which does not use the template parameters. Have a base class, put all non-template related things there, your template class should derive from it.
To answer your questions:
yes, everywhere where you need to instantiate the template, you need to see the full definition of the class and it's functions
yep, but put that into the base class
yes, see above
EDIT: One of the reasons to move to base class is code bloating (this expression actually exist, you can google it for more info): If you don't move the template unrelated code to a base class, the very same template independent code will be copied for all instantiation of your template, which means a lot of unnecessary code. If you put it to a base class, you will only have this code once.
Yes. On the plus side, the code is only generated when the metod is actually used for the specialization.
Yes. However, there is no (other then design choice) need for a static method to be a memeber of the templated class if it has no use for the templated parameter.
Yes. The size and memory layout of the structure is determined by the template parameter.

Class template can be instantiated without members?

The Wikipedia article says this:
instantiating a class template does not cause its member definitions to be instantiated.
I can't imagine any class in C++ being instantiated, whether from a template or not, where that classes members were not also instantiated?
Many early C++ compilers instantiated all member functions, whether you ever called them or not.
Consider, for example, std::list, which has a sort member function. With a current, properly functioning compiler, you can instantiate list over a type that doesn't support comparison. If you try to use list::sort, it will fail, because you don't support comparison. As long as you don't call sort for that list, it's all fine though, because list<T>::sort won't be instantiated unless you call it.
With those older, poorly functioning compilers, however, trying to create list<T> meant that list<T>::sort was instantiated even though you never used it. The existence of list::sort meant that you needed to implement < for T, just to create a list<T>, even if you never actually used sort on a list of that type at all.
The standard clearly says that (both non-template and template) member methods instantiation should happen only when used.
An excerpt from C++ standard (N3690 - 14.7.1(2) Implicit instantiation)
2 Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
Methods of a class are also members. Class Template methods are instantiated when they are called for that instantiated class. So it is possible that those member methods are never instantiated.

Forward Declaration of a Base Class

I'm trying to create proper header files which don't include too many other files to keep them clean and to speed up compile time.
I encountered two problems while doing this:
Forward declaration on base classes doesn't work.
class B;
class A : public B
{
// ...
}
Forward declaration on STD classes doesn't work.
namespace std
{
class string;
}
class A
{
string aStringToTest;
}
How do I solve these problems?
The first problem you can't solve.
The second problem is not anything to do with standard library classes. It's because you declare an instance of the class as a member of your own class.
Both problems are due to the requirement that the compiler must be able to find out the total size of a class from its definition.
However, the compiler can work out the size of a pointer to a class, even if it doesn't yet have the full definition of it. So a possible solution in such cases is to have a pointer (or reference) member in the consuming class.
Not much help in the base class case, because you won't get an 'is a' relationship.
Nor is it worth doing for something like std::string. Firstly, it's supposed to be a convenient wrapper around a character buffer, to save you from doing memory management on something so simple. If you then hold a pointer to it, just to avoid including the header, you're probably taking a good idea too far.
Secondly (as pointed out in a comment), std::string is a typedef to std::basic_string<char>. So you need to forward declare (and then use) that instead, by which time things are getting very obscure and hard to read, which is another kind of cost. Is it really worth it?
As answered before by Earwicker, you can not use forward declarations in any of those cases as the compiler needs to know the size of the class.
You can only use a forward declaration in a set of operations:
declaring functions that take the forward declared class as parameters or returns it
declaring member pointers or references to the forward declared class
declaring static variables of the forward declared type in the class definition
You cannot use it to
declare a member attribute of the given type (compiler requires size)
define or create an object of the type or delete it
call any static or member method of the class or access any member or static attribute
(did I forget any?)
Take into account that declaring an auto_ptr is not the same as declaring a raw pointer, since the auto_ptr instantiation will try to delete the pointer when it goes out of scope and deleting requires the complete declaration of the type. If you use an auto_ptr in to hold a forward declared type you will have to provide a destructor (even if empty) and define it after the full class declaration has been seen.
There are also some other subtleties. When you forward declare a class, you are telling the compiler that it will be a class. This means that it cannot be an enum or a typedef into another type. That is the problem you are getting when you try to forward declare std::string, as it is a typedef of a specific instantiation of a template:
typedef basic_string<char> string; // aproximate
To forward declare string you would need to forward declare the basic_string template and then create the typedef. The problem is that the standard does not state the number of parameters that basic_string template takes, it just states that if it takes more than one parameter, there rest of the parameters must have a default type so that the expression above compiles. This means that there is no standard way for forward declaring the template.
If, on the other hand you want to forward declare a non-standard template (non STL, that is) you can do it for as long as you do know the number of parameters:
template <typename T, typename U> class Test; // correct
//template <typename T> class Test; // incorrect even if U has a default type
template <typename T, typename U = int> class Test {
// ...
};
At the end, the advice that was given to you by Roddy: forward declare as much as you can, but assume that some things must be included.
In both cases the compiler needs to know the size of the type. Therefore, a forward declaration will not suffice. A base class could add members or require a virtual table. The string member would require the size of the class to be increase to store the size of the STL string class.
Forward declaring STL classes is often inadvisable since the implementations commonly include explicit template instantiations that speed up compilation.
You're trying too hard to solve something that isn't actually a problem. Use the header files you need, and reduce - WHERE POSSIBLE - the requirement for them. But don't try and take it to extremes because you'll fail.
In some cases, the PIMPL idiom may help you, but not here.
For your base classes, you need to have the full type definition, not just a declaration. Derived type headers will need to #include the header for their base classes.
For classes in the std namespace, you must include the proper header - <string> in this case - and then do one of 3 things:
Fully qualify the type: std::string
aStringToTest
Put a using declaration for just
that type: using std::string;
Put in a using declaration for the
std namespace: using namespace std;
> Seems that forward declaration is useless for base classes and stl classes.
Correction...
Forward declaration is INAPPROPRIATE for base classes and object member. (It's not "useless", it is "inapplicable".)
A base class MUST be declared (not forward declared) when being declared as a based class of another class.
An object member MUST be declared (not forward declared) when being declared by another class, or as parameter, or as a return value. NOTE: by-reference or by-pointer does not have that constraint.
Correction...
Forward declaration of STL classes is -- as per ISO 14882 -- undefined behavior.
http://www.gotw.ca/gotw/034.htm