turning a non-template class into a template - c++

I have a self made data structure (for example linked list) that works well, but when I made the class I did it based around strings, but now I want to take that data structure, and use it to hold another self made data type. I know that this involves templates (the ability to take a working data structure and apply any data type to it), but I have not really worked with them.
what steps should I follow to turn a non-template class into a template class?

The main thing you need to do is put the template specification in front:
template <class T>
class A {
...
};
Then use T instead of using your string type.
There are lots of other things to consider when creating templates, but it depends on the particular situation.
You will specify your new type when you use the template:
A<MyType> my_object;

that is basic actions
Move all method definitions of your class from .cpp to .h file
Put template specifications (template <class T>) before all declarations and definitions
Change all class name specifiers to template names, i.e. A::A(){} should became A<T>::A(){}
If it required, change the names of method calls to ones with type parameters
Change all entries of the previous type to the type parameter name
can be a lot of the other things of course.

Related

Template class forward declaration with default argument [duplicate]

Suppose we have a class template with default template parameter:
template <typename T = int>
class Foo {};
We can omit angle brackets when creating a variable inside a function:
int main()
{
Foo a; // gets properly deduced as Foo<int>
}
But we can't do that for member variables:
struct S
{
Foo a; // Deduce Foo<int>
};
We can't have derivative types such as this:
Foo* ptr; // Foo<int>*
Foo& ref; // Foo<int>&
int Foo::* mem_ptr; // int Foo<int>::*
std::function<Foo(const Foo&)> fn; // std::function<Foo<int>(const Foo<int>&)>
We can't accept parameters and return them:
Foo Bar(const Foo&); // Foo<int> (*)(const Foo<int>&)
Why? Is this considered a bug in the standard? Is there a proposal to fix it? Are there any actual problems with omitting angle brackets?
My use case:
I have a class template which provides default argument. The template parameter is an expert-only feature that I myself never use but it is there for those 1% of experts who want that total flexibility. Now for other 99% I want to hide the fact that Foo is actually a class template but it doesn't work because users have to type Foo<> when declaring it as a member variable, current solution is this:
template <typename T = int>
class BasicFoo {};
using Foo = BasicFoo<>;
But it complicates implementation code and is not elegant at all.
Is this considered a bug in the standard?
No.
Templates are a named construct which generates another construct (classes/functions/variables) based on a set of parameters. The name of a template is not the name of the construct which it generates. The name of a template is just the name of the template; to name the thing the template generates, you must provide the template parameters.
Foo is the name of a template; Foo<> is the name of a class generated by that template and its associated template parameters.
There are a couple of places where C++ allows a template to be used in such a way that its parameters are deduced from a sequence of expressions. But these are very specific places, created for convenience purposes. They do not exist for the purpose of hiding the fact that a name represents a template rather than the generated construct.
Is there a proposal to fix it?
There is nothing broken to fix. And there are at present no proposals adding changes in this way.
Are there any actual problems with omitting angle brackets?
Define "actual problem". Is it theoretically possible to have the language altered so that, if all of a template's parameters are defaulted, the name of the template can be used without template parameters to simultaneously mean the template and the thing the template generates?
It is probably possible. But it would be complicated to specify. You would need a serious spec-doctor, one who understands the C++ grammar at a deep level, to know for sure whether it is possible, and what exactly would need to be changed to do it.
But at the end of the day, it would only ever be useful for a small, select set of templates: templates that have default values for all of its parameters. The real question is whether that is a common enough case to be worth the effort.
I don't consider myself a language expert, but my stance would be that the problem your proposal tries to tackle is solved much simpler in the same way std::(basic_)string does it.
We have
template<
class CharT,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
> class basic_string;
and then a set of typedefs for "non-expert" users, such as std::string for std::basic_string<char>.
If an expert user wants to make use of the other template parameters, they can themselves define a type alias, which is nice and coherent with the above. Moreover, this cleanly separates the template from the types that are created from it.
Your suggestion of allowing templates with defaults for all parameters to be named by MyTemplate alone, instead of requiring MyTemplate<>, or making use of using MyTemplate = MyBasicTemplate<>;, has the following issues:
It complicates the grammar and specification of the language. You need to touch the allowed syntax of all the contexts mentioned in your question, adding the ability to use a template name where a type name would be expected, but only if the relevant template has default values for all template parameters. And if you don't change all of them, you introduce weirdly inconsistent behavior.
There is some overlap between your suggestion and CTAD, but CTAD is decidedly about reducing type verbosity for initialization. CTAD offers significant comfort within its scope and is extensible through deduction guides, whereas your proposal's syntactic sugar is only relevant in a tiny usage niche, with much smaller benefits.
There is the danger of accidentally using the wrong template parameters (did you mean the default template parameters or did you just forget to specify the ones you wanted?). Even if that is not a concern in your use case, the standard would have to concern itself with that potential issue.
There is also the danger of your suggestion conflicting with deduction guides. Who should win?
Your problem is easily and conveniently solved with existing language tools (see above). I disagree that this "complicates" implementation code (complexity is literally only increased by a single typedef/using, (re)naming your template is absolutely trivial work) or that it is inelegant.
Overall, the problem you intend to solve (saving library implementers a using, or users a <> (or using), exclusively for all-defaulted templates) is fringe at best and will not be a sufficient motivation for significantly altering several core aspects the language. That's my prediction at least.

std::optional with optional variadic template [duplicate]

Suppose we have a class template with default template parameter:
template <typename T = int>
class Foo {};
We can omit angle brackets when creating a variable inside a function:
int main()
{
Foo a; // gets properly deduced as Foo<int>
}
But we can't do that for member variables:
struct S
{
Foo a; // Deduce Foo<int>
};
We can't have derivative types such as this:
Foo* ptr; // Foo<int>*
Foo& ref; // Foo<int>&
int Foo::* mem_ptr; // int Foo<int>::*
std::function<Foo(const Foo&)> fn; // std::function<Foo<int>(const Foo<int>&)>
We can't accept parameters and return them:
Foo Bar(const Foo&); // Foo<int> (*)(const Foo<int>&)
Why? Is this considered a bug in the standard? Is there a proposal to fix it? Are there any actual problems with omitting angle brackets?
My use case:
I have a class template which provides default argument. The template parameter is an expert-only feature that I myself never use but it is there for those 1% of experts who want that total flexibility. Now for other 99% I want to hide the fact that Foo is actually a class template but it doesn't work because users have to type Foo<> when declaring it as a member variable, current solution is this:
template <typename T = int>
class BasicFoo {};
using Foo = BasicFoo<>;
But it complicates implementation code and is not elegant at all.
Is this considered a bug in the standard?
No.
Templates are a named construct which generates another construct (classes/functions/variables) based on a set of parameters. The name of a template is not the name of the construct which it generates. The name of a template is just the name of the template; to name the thing the template generates, you must provide the template parameters.
Foo is the name of a template; Foo<> is the name of a class generated by that template and its associated template parameters.
There are a couple of places where C++ allows a template to be used in such a way that its parameters are deduced from a sequence of expressions. But these are very specific places, created for convenience purposes. They do not exist for the purpose of hiding the fact that a name represents a template rather than the generated construct.
Is there a proposal to fix it?
There is nothing broken to fix. And there are at present no proposals adding changes in this way.
Are there any actual problems with omitting angle brackets?
Define "actual problem". Is it theoretically possible to have the language altered so that, if all of a template's parameters are defaulted, the name of the template can be used without template parameters to simultaneously mean the template and the thing the template generates?
It is probably possible. But it would be complicated to specify. You would need a serious spec-doctor, one who understands the C++ grammar at a deep level, to know for sure whether it is possible, and what exactly would need to be changed to do it.
But at the end of the day, it would only ever be useful for a small, select set of templates: templates that have default values for all of its parameters. The real question is whether that is a common enough case to be worth the effort.
I don't consider myself a language expert, but my stance would be that the problem your proposal tries to tackle is solved much simpler in the same way std::(basic_)string does it.
We have
template<
class CharT,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
> class basic_string;
and then a set of typedefs for "non-expert" users, such as std::string for std::basic_string<char>.
If an expert user wants to make use of the other template parameters, they can themselves define a type alias, which is nice and coherent with the above. Moreover, this cleanly separates the template from the types that are created from it.
Your suggestion of allowing templates with defaults for all parameters to be named by MyTemplate alone, instead of requiring MyTemplate<>, or making use of using MyTemplate = MyBasicTemplate<>;, has the following issues:
It complicates the grammar and specification of the language. You need to touch the allowed syntax of all the contexts mentioned in your question, adding the ability to use a template name where a type name would be expected, but only if the relevant template has default values for all template parameters. And if you don't change all of them, you introduce weirdly inconsistent behavior.
There is some overlap between your suggestion and CTAD, but CTAD is decidedly about reducing type verbosity for initialization. CTAD offers significant comfort within its scope and is extensible through deduction guides, whereas your proposal's syntactic sugar is only relevant in a tiny usage niche, with much smaller benefits.
There is the danger of accidentally using the wrong template parameters (did you mean the default template parameters or did you just forget to specify the ones you wanted?). Even if that is not a concern in your use case, the standard would have to concern itself with that potential issue.
There is also the danger of your suggestion conflicting with deduction guides. Who should win?
Your problem is easily and conveniently solved with existing language tools (see above). I disagree that this "complicates" implementation code (complexity is literally only increased by a single typedef/using, (re)naming your template is absolutely trivial work) or that it is inelegant.
Overall, the problem you intend to solve (saving library implementers a using, or users a <> (or using), exclusively for all-defaulted templates) is fringe at best and will not be a sufficient motivation for significantly altering several core aspects the language. That's my prediction at least.

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.

Using extern template instantiation for nested types / typedefs

Assume I have a class Module<Setting> that I want to instantiate externally. (reducing compilation time...)
I created a Module.cpp that contains template class Module<Setting>; and added the extern declaration in the header. This works fine.
Now I want to wrap this Module instantiation in another class, for example like this:
template<template<typename> class M, typename First>
struct TrivialInstantiator {
typedef M<First> type;
};
This does not seem to work, i.e. the compilation time for other compilation units does not change (in comparison to not using the extern declaration at all). My question: Why is that so? Can I somehow make it work?
(I tried to read the relevant sections of the standard, but I couldn't quite figure it out...)
Rationale for my question:
I have a larger number of Settings, and people may create new Settings that are not familiar with these details. If I simply create a list of extern template declarations for Module<Setting1>, Module<Setting2>, etc., this is not only tedious but will also tend to produce errors when users forget to add the template instantiation in the cpp file for example.
Therefore I tried to create a list of Settings (with boost::mpl) at one point and use this list of Settings to instantiate all of them at once.
Edit: This other question is about how extern works altogether, it's not about how it handles nested types or typedefs.
Update: I read ยง14.7.2.8 several times again:
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 and members that are templates) [...].
I tried the following:
template<template<typename> class M, typename First>
struct TrivialInstantiator {
M<First> member;
};
As this does not work either: Is this member considered a template as in not including members [...] that are templates? (Isn't it a fully instantiated template that is something different...? Is there any way to workaround that?)

(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.