I just finished creating my binary tree class only to realise that I was supposed to make it as a template. I've spent hours now trying to get to convert it to a template, but I keep getting a multitude of errors ranging from "invalid use of template-name" to "extra qualification of a member". I am new to the concept of templates but I have an idea of what I'm trying to achieve.
BTree.cpp
#include <iostream>
#include <string>
#include "BTree.h"
using namespace std;
BTree::BTree(board startboard, string startplayer)
{
treeboard = startboard;
player = startplayer;
root = new BTNode(treeboard, player,-1,-1);
}
BTree::~BTree()
{
delete root;
}
int BTree::sumtree()
{
if (root->getvalue(-1) > root->getvalue(1))
return root->getchildposition(-1);
else
return root->getchildposition(1);
}
BTree.h
#include <string>
#include "BTNode.h"
#include "board.h"
using namespace std;
class BTree
{
public:
BTree(board startboard, string startplayer);
~BTree();
int sumtree();
private:
string player;
board treeboard;
BTNode *root;
};
'startplayer' is currently a string, I would like this to be the generic template type.
What should my process be for turning this into a single template file?
Well, let's first look what errors or other deficits your code has:
Your BTree has a custom dtor, because it holds resources. But you are violating the rule-of-3:
You need to define or delete, at minimum, your assignment-operator and copy-ctor.
As an alternative (preferable), change BTNode *root; to use std::unique_ptr.
The first thing included in the implementation-file should always be its own header, to find broken dependencies in the header.
The header should include everything neccessary to use it, and not one bit more.
Now, there are good reasons why templates are usually header-only:
The compiler needs the definition to instantiate it.
Use the opportunity to move some of the functions into the class.
Next, you define a template like this:
template<class T> class BTree {
int BTree::sumtree();
};
And non-inline members like this:
template<class T> int BTree<T>::sumtree() {
return //...
}
In the template, you can use the type-argument like a normal type.
A note on BTNode: It's an implementation-detail of BTree, so put its definition into the class (which makes templating it the same and using it easier as well.)
Alternatively, if you don't actually need all the template-arguments for BTNode as well (or want to share its implementation), template it separately.
Don't forget to change all references from BTree though.
First of all to use templates in C++ all of your executable code NEEDS to be in the .h file so it is available at compile time.
Then to template your class, the usual way is to make it like :
template<class T>
class BTree
{
Btree(T startPlayer)
{
player = startPlayer;
}
// ... snip ...
T player;
}
Related
I have used templates to implement path policies.
#include <fstream>
#include <DefaultPolicy.h>
template<typename PathPolicy = DefaultPolicy>
class FileReader
{
public:
double getNextNumber();
private:
PathPolicy pp;
readNumbers() { std::ifstream myFile(pp.path); }; //And so on
};
I implemented:
[HEADER]
struct DefaultPolicy
{
public:
std::string path
DefaultPolicy()
} ;
[IMPLEMENTATION]
DefaultPolicy::DefaultPolicy() : path("."){}
So now I want to implement lots of different policies like:
[HEADER]
struct UnitTestPolicy
{
public:
std::string path
UnitTestPolicy()
} ;
[IMPLEMENTATION]
UnitTestPolicy::UnitTestPolicy() : path("unittests/resources"){}
[HEADER]
struct OperationalPathPolicy
{
public:
std::string path
OperationalPathPolicy()
} ;
[IMPLEMENTATION]
OperationalPathPolicy::OperationalPathPolicy() : path("/sw/cm/resources"){}
I'm not sure how to switch my policies. These are compile-time choices, and I can select the target that I'm building for, but the only idea I have is fall back to macros to make a selection. If I do that, then I don't really need the template abstraction for the policy.
How should I select a policy class at build time?
but the only idea I have is fall back to macros to make a selection
True.
If I do that, then I don't really need the template abstraction for the policy.
False. The template abstraction helps you to minimize use of the preprocessor and isolate your policies cleanly.
You can also force instantiation of your template class in a .cpp file to avoid compile-time overhead caused by templates, as you are aware of all the possible policy types.
// filereaderimpl.hpp
namespace detail
{
template<typename PathPolicy>
class FileReaderImpl { /* ... */ };
}
// filereader.hpp
#include <fileheaderimpl.hpp>
#ifdef SOME_BUILD_TIME_CHOICE
using FileReader = detail::FileHeaderImpl<SomePolicy>;
#else
using FileReader = detail::FileHeaderImpl<SomeOtherPolicy>;
#endif
EDIT: I misread the problem, the solution below will allow policy selection at runtime, you asked for selection at build time.
I think your problem would be better served by inheritance.
So you have a base PathPolicy (you can call it whatever i.e. DefaultPolicy) class and then have other policies inherit from the PathPolicy class.
So your UnitTestPolicy becomes
struct UnitTestPolicy : public PathPolicy
{
public:
UnitTestPolicy()
{
path = "blah//blah";
}
} ;
Then in your file reader, use the base class only to abstract other implementations of the policy class. That way your file reader doesn't care what the policy is; it's just going to read the file.
Working example here.
I am experimenting with the Builder/Fluent style of creating objects trying to extend some ideas presented in a course. One element I immediately didn't like with my test implementation was the large number of additional header files the client needs to include for the process to work, particularly when I wish to make use of public/private headers via the pImpl idiom for purposes of providing a library interface. I'm not entirely certain whether the problem lies with my implementation or I'm just missing an obvious 'last step' to achieve what I want.
The general gist is as follows (using the toy example of Pilots):
Firstly the client code itself:
(Note: for brevity, various boilerplate and irrelevant code has been omitted)
Pilot p = Pilot::create()
.works().atAirline("Sun Air").withRank("Captain")
.lives().atAddress("123 Street").inCity("London")
What's happening here is:
In Pilot.h, the Pilot class is defined with a static member method called create() that returns an instance of a PilotBuilder class defined in PilotBuilder.h and forward declared in Pilot.h
Essentially the PilotBuilder class is a convenience builder only used to present builders of the two different facets of a Pilot (.works() and .lives()), letting you switch from one builder to another.
Pilot.h:
class PilotBuilder;
class Pilot {
private:
// Professional
string airline_name_, rank_;
// Personal
string street_address_, city_;
Pilot(){}
public:
Pilot(Pilot&& other) noexcept;
static PilotBuilder create();
friend class PilotBuilder;
friend class PilotProfessionalBuilder;
friend class PilotPersonalBuilder;
};
Pilot.cpp:
#include "PilotBuilder.h"
PilotBuilder Pilot::create() {
return PilotBuilder();
}
// Other definitions etc
PilotBuilder.h
#include "public/includes/path/Pilot.h"
class PilotProfessionalBuilder;
class PilotPersonalBuilder;
class PilotBuilder {
private:
Pilot p;
protected:
Pilot& pilot_;
explicit PilotBuilder(Pilot& pilot) : pilot_{pilot} {};
public:
PilotBuilder() : pilot_{p} {}
operator Pilot() {
return std::move(pilot_);
}
PilotProfessionalBuilder works();
PilotPersonalBuilder lives();
};
PilotBuilder.cpp
#include "PilotBuilder.h"
#include "PilotProfessionalBuilder.h"
#include "PilotPersonalBuilder.h"
PilotPersonalBuilder PilotBuilder::lives() {
return PilotPersonalBuilder{pilot_};
}
PilotProfessionalBuilder PilotBuilder::works() {
return PilotProfessionalBuilder{pilot_};
}
As you can imagine the PilotProfessionalBuilder class and the PilotPersonalBuilder class simply implement the methods relevant to that particular facet eg(.atAirline()) in the fluent style using the reference provided by the PilotBuilder class, and their implementation isn't relevant to my query.
Avoiding the slightly contentious issue of providing references to private members, my dilemma is that to make use of my pattern as it stands, the client has to look like this:
#include "public/includes/path/Pilot.h"
#include "private/includes/path/PilotBuilder.h"
#include "private/includes/path/PilotProfessionalBuilder.h"
#include "private/includes/path/PilotPersonalBuilder.h"
int main() {
Pilot p = Pilot::create()
.works().atAirline("Sun Air").withRank("Captain")
.lives().atAddress("123 Street").inCity("London");
}
What I cannot figure out is:
How do I reorder or reimplement the code so that I can simply use #include "public/includes/path/Pilot.h" in the client, imagining say, that I'm linking against a Pilots library where the rest of the implementation resides and still keep the same behaviour?
Provided someone can enlighten me on point 1., is there any way it would be then possible to move the private members of Pilot into a unique_ptr<Impl> pImpl and still keep hold of the static create() method? - because the following is obviously not allowed:
:
PilotBuilder Pilot::create() {
pImpl = make_unique(Impl); /* struct containing private members */
return PilotBuilder();
}
Finally, I am by no means an expert at any of this so if any of my terminology is incorrect or coding practices really need fixing I will gladly receive any advice people have to give. Thank you!
I am relatively new to c++ and am having a heck of a time getting my main program to instantiate my class. I am used to java so I'm not sure if I am mixing up the two languages as I attempt to do this and that is my problem or maybe I just don't understand the concept correctly.
The object of my program: The object of this program is to create a template class from an interface that will make a sorted array that you can add and remove items from it while keeping it sorted.
Note: Please help me actually understand this process as to just telling me the exact code to use because I really want to understand what I am doing wrong for next time.
Step 1: I created my sorted interface:
sortedInterface.h
#ifndef _SORTED_INTERFACE
#define _SORTED_INTERFACE
#include <vector>
using namespace std;
template<class ListItemType>
class sortedInterface
{
public:
virtual bool sortedIsEmpty();
virtual int sortedGetLength();
virtual bool sortedInsert(ListItemType newItem);
virtual bool sortedRemove(ListItemType anItem);
virtual bool sortedRetrieve(int index, ListItemType dataItem);
virtual int locatePosition(ListItemType anItem);
}; // end SortedInterface
#endif
then I used the interface to create the sorted.h file:
sorted.h
#include "sortedInterface.h"
#include <iostream>
#ifndef SORTED_H
#define SORTED_H
using namespace std;
template<class ListItemType>
class sorted
{
public:
sorted();
sorted(int i);
bool sortedIsEmpty();
int sortedGetLength();
bool sortedInsert(ListItemType newItem);
bool sortedRemove(ListItemType anItem);
bool sortedRetrieve(int index, ListItemType dataItem);
int locatePosition(ListItemType anItem);
protected:
private:
const int DEFAULT_BAG_SIZE = 10;
ListItemType items[];
int itemCount;
int maxItems;
};
#endif // SORTED_H
and finally I created the sorted.cpp (I only included the constructor for now as I can't even get that working)
#include "sorted.h"
#include <iostream>
using namespace std;
template<class ListItemType>
sorted<ListItemType>::sorted()
{
itemCount = 0;
items[DEFAULT_BAG_SIZE];
maxItems = DEFAULT_BAG_SIZE;
}
My main program:
#include "sortedInterface.h"
#include "sorted.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
sorted<string> sorted1 = new sorted();
return 0;
};
Any help is appreciated in explaining where my logic is failing on this and any hints on how to properly execute my task. Thanks!
1) operator "new" returns a pointer, not an object.
sorted<string>* sorted1 = new sorted<string>();
2) However, in your small example, there is no need to create sorted1 using "new".
sorted<string> sorted1;
One word of advice -- Java is not C++. You made the two mistakes that many first-time Java programmers make when writing C++ code, namely 1) believing that to create an object, you must use "new", and 2), that "new" returns a reference.
There are a few things wrong with your interface/implementation. A class template is usually implemented entirely in the header in which it's declared; this is because the compiler creates a whole new type for each type you use with your template.
Second, in your sortedInterface template, you've made the members virtual which still requires a definition, but you do not supply one. You can mark your member functions with = 0; to make them all pure virtual, which means the classes that inherit your sortedInterface will have to implement those members instead.
Third, as PaulMcKenzie pointed out, operator new() returns a pointer to a heap-allocated object, but you're expecting a value type.
Finally, please take a look at smart pointers if you're using naked new()s everywhere.
I notice the following additional anomalies in the entire implementation:
An interface is something which should be non-instantiable but it is
instantiable in your case (because there is not even a single pure
virtual function in your so called interface) Standard rule is to
make all the functions in the interface pure virtual (=0)
class Sorted does not inherit from the so-called interface
sortedInterface
You have not defined all versions of your constructor in your class
Sorted
If you want the polymorphism to work (Interface to Concrete), you
need to have virtual class destructors in both the interface and
concrete class
I am developing a list in which I have used some protected variables count, entry[maxlist] etc.
List.h
class List
{
public:
//etc etc
protected:
int count;
int entry[maxlist];
};
Sortable_list.h
typedef Key Record;
class Sortable_list:public List<Record>
{
void selection_sort()
{
for(int position=count-1;position>0;i--) // Count is not declared in the scope
{
int max=max_key(0, position);
swap(max, position);
}
}
};
Is something wrong with inheriting the List to Sortable List? Why is it showing count out of scope?
#Edit: After seeing your whole code it becomes clearer. You're having ambiguities because of your includes, it will compile with msvc, because it handles such cases silently, but for g++ you should explicitly state that count is from this class, by doing this->count. You also had problems because of std::range_error, which could be avoided by removing using namespace std or replacing range_error with ::range_error which will indicate that you want the global scope. Another problem with your code is that, you were using an undefined variable i in your Sortable_list. The fixed code that compiles with g++ and msvc: http://codepad.org/7V70rNqf
I don't want to sound rude, but I strongly suggest you read a book on C++, your current code is very anti-idiomatic, and could be made generic with a smaller amount of code.
Why don't you use sort function template from <algorithm> header? All you need to write just one small Compare function.
Look like your List is not a template class, so List< Typename > doesn't exist ..
Also, you can use std::set<T> as a template class for sorted container => http://www.sgi.com/tech/stl/set.html
In our library we have a number of "plugins", which are implemented in their own cpp files. Each plugin defines a template function, and should instantiate this function over a whole bunch of types. The number of types can be quite large, 30-100 of them, and can change depending on some compile time options. Each instance really have to be compiled and optimized individually, the performance improves by 10-100 times. The question is what is the best way to instantiate all of these functions.
Each plugin is written by a scientist who does not really know C++, so the code inside each plugin must be hidden inside macros or some simple construct. I have a half-baked solution based on a "database" of instances:
template<int plugin_id, class T>
struct S
{
typedef T (*ftype)(T);
ftype fp;
};
// By default we don't have any instances
template<int plugin_id, class T> S::ftype S::fp = 0;
Now a user that wants to use a plugin can check the value of
S<SOME_PLUGIN,double>::fp
to see if there is a version of this plugin for the double type. The template instantiation of fp will generate a weak reference, so the linker will use the "real" instance if we define it in a plugin implementation file. Inside the implementation of SOME_PLUGIN we will have an instantiation
template<> S<SOME_PLUGIN,double>::ftype S<SOME_PLUGIN,double>::fp =
some_plugin_implementation;
This seems to work. The question is if there is some way to automatically repeat this last statement for all types of interest. The types can be stored in a template class or generated by a template loop. I would prefer something that can be hidden by a macro. Of course this can be solved by an external code generator, but it's hard to do this portably and it interfers with the build systems of the people that use the library. Putting all the plugins in header files solves the problem, but makes the compiler explode (needing many gigabytes of memory and a very long compilation time).
I've used http://www.boost.org/doc/libs/1_44_0/libs/preprocessor/doc/index.html for such magic, in particular SEQ_FOR_EACH.
You could use a type list from Boost.MPL and then create a class template that recursively eats that list and instantiates every type. This would however make them all nested structs of that class template.
Hmm, I don't think I understand your problem correctly, so apologies if this answer is way off the mark, but could you not have a static member of S, which has a static instance of ftype, and return a reference to that, this way, you don't need to explicitly have an instance defined in your implementation files... i.e.
template<int plugin_id, class T>
struct S
{
typedef T (*ftype)(T);
static ftype& instance()
{
static ftype _fp = T::create();
return _fp;
}
};
and instead of accessing S<SOME_PLUGIN,double>::fp, you'd do S<SOME_PLUGIN,double>::instance(). To instantiate, at some point you have to call S<>::instance(). Do you need this to happen automagically as well?
EDIT: just noticed that you have a copy constructor, for ftype, changed the above code.. now you have to define a factory method in T called create() to really create the instance.
EDIT: Okay, I can't think of a clean way of doing this automatically, i.e. I don't believe there is a way to (at compile time) build a list of types, and then instantiate. However you could do it using a mix... Hopefully the example below will give you some ideas...
#include <iostream>
#include <typeinfo>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/algorithm.hpp>
using namespace std;
// This simply calls the static instantiate function
struct instantiate
{
template <typename T>
void operator()(T const& x) const
{
T::instance();
}
};
// Shared header, presumably all plugin developers will use this header?
template<int plugin_id, class T>
struct S
{
typedef T (*ftype)(T);
static ftype& instance()
{
cout << "S: " << typeid(S<plugin_id, T>).name() << endl;
static ftype _fp; // = T::create();
return _fp;
}
};
// This is an additional struct, each plugin developer will have to implement
// one of these...
template <int plugin_id>
struct S_Types
{
// All they have to do is add the types that they will support to this vector
static void instance()
{
boost::fusion::vector<
S<plugin_id, double>,
S<plugin_id, int>,
S<plugin_id, char>
> supported_types;
boost::fusion::for_each(supported_types, instantiate());
}
};
// This is a global register, so once a plugin has been developed,
// add it to this list.
struct S_Register
{
S_Register()
{
// Add each plugin here, you'll only have to do this when a new plugin
// is created, unfortunately you have to do it manually, can't
// think of a way of adding a type at compile time...
boost::fusion::vector<
S_Types<0>,
S_Types<1>,
S_Types<2>
> plugins;
boost::fusion::for_each(plugins, instantiate());
}
};
int main(void)
{
// single instance of the register, defining this here, effectively
// triggers calls to instanc() of all the plugins and supported types...
S_Register reg;
return 0;
}
Basically uses a fusion vector to define all the possible instances that could exist. It will take a little bit of work from you and the developers, as I've outlined in the code... hopefully it'll give you an idea...