I am trying to implement my own container (in my demonstration called Manager), which stores another templated container (e.g Node<T>).
Therefore I am trying to instantiate an object like Mgr<Node<T>>.
After reading through all of the template template-articles on here, I came to the following demonstration code.
#include <iostream>
template<typename T>
struct Node {
T data;
int id;
};
template<template<typename> class Container, typename T>
struct Mgr {
Container<T> nodes;
int id;
void print()
{
std::cout << this->id;
}
};
int main() {
Mgr<Node<char>, char> mgr;
mgr.print();
return 0;
}
Compiling this still gives me the error message: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class Container, class T> struct Mgr...Expected a class template, got Node<char>
Is my function definition wrong, or do my instantiation parameters incorrect?
template<typename> class Container expect that you pass a template as Container, Node<char> is not a template, it's a concrete type.
You want
Mgr<Node, char> mgr;
Related
I want to use my class with the template.
in main:
int main(void)
{
HexAdapter<vector> foo;
// maybe?
// HexAdapter<vector<Cell>> foo;
return 0;
}
I tried something like this
template <typename T>
class HexAdapter
{
public:
HexAdapter();
private:
T<T<Cell>> hexCells;
};
For the reason of this, Normally I used like this vector<vector<Cell>> hexCells But I want to work with all STL Containers with random access iterator.
You can achieve the HexAdapter<std::vector> syntax by relying on a template template parameter, i.e., a template parameter which is, in turn, a class template (or an alias template):
struct Cell { /* ... */ };
template<template<typename...> class Cont>
class HexAdapter {
Cont<Cont<Cell>> hexCells;
/* ... */
};
The template argument to the class template HexAdapter (i.e., the argument to the Cont parameter) must be a class template itself (e.g., std::vector or std::deque):
auto main() -> int {
HexAdapter<std::vector> foo;
HexAdapter<std::deque> bar;
}
I have two similar structures which are slightly different in the packing. They are used in a member function of the another class. So can I write some template methods, with these structure as template parameter, to avoid duplication. So how to pass struct name itself for template initialization?
struct header
{
char symbol[6];
};
struct headerV8
{
int id;
char symbol[8];
};
class connection
{
connectionMgr _mgr;
public:
// here I want to pass T as only type; Class itself is not a template class
// but its method is template function.
template<class T>
void request(T);
};
//template parameter is used to decide which struct to use header or headerV8.
<template T>
void connection::request(T)
{
T a;
strcpy(a.symbol, "AAPL");
cout << a.symbol;
mgr.socketSend(a);
}
calls to request
if(versionV8)
conn.request(headerV8);
else
conn.request(heaver);
I am forgetting the syntax in this moment. Can someone please help? Basically below is what I am trying to do. I don't mind to set it up to take two template arguments if needed meaning runSchedule<SchedT, TaskT>() if this is easier. Also if you could comment on how to get the using alias to work for scheduler_type and scheduler_type::task_type to be recognized as types within the function.
#include <iostream>
class TestTask {
public:
int x;
};
template <typename TaskT>
class TestScheduler {
public:
typedef TaskT task_type;
int y;
};
template <template<class> class SchedT>
void runSchedule() {
typedef SchedT scheduler_type;
scheduler_type sched;
scheduler_type::task_type task;
}
int main() {
runSchedule<TestScheduler<TestTask> >();
}
You don't need a template template-parameter for what you're trying to do.
template < class SchedT>
void runSchedule() {
typedef SchedT scheduler_type; // <-- typedef syntax was backwards
scheduler_type sched;
typename scheduler_type::task_type task;
// ^^^^^ need typename keyword when referring to nested dependent type
}
The template<class> class SchedT in your template function argumets?
Replace with class SchedT.
The earlier syntax is for passing the template, the later a class generated by the template.
using namespace std;
#include <vector>
#include <string>
template <class T>
struct ValNode {
string id;
T value;
};
class ValTable {
public:
ValTable();
template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
template<class T>
std::vector<ValNode<T>*> vals;
};
complier error:error: data member 'vals' cannot be a member template
i did try to use T* value in the struct, but i didnt work out.
I didnt use any of the functions in codes yet. was just trying to compling it into *.o file (with .cpp file also).
As the error says, variables (including data members) can't be templates; only classes and functions can be.
It looks like you want the table to be able to hold values of various different types, specified at run-time according to which types are passed to add(). For that, you need dynamic types, which aren't directly supported in C++. You might consider libraries like Boost.Any or Boost.Variant for that.
On the other hand, maybe you just want to store a single type in each table, and different types in different tables. In that case, the class itself will need to be a template:
template <typename T>
class ValTable {
public:
ValTable();
void add(string,T);
const bool find(string);
void remove(string);
private:
std::vector<ValNode<T>*> vals;
};
In C++ you can have template methods in a class, but not template data members.
For example:
template<typename T, int n>
struct FixedVector {
T x[n];
FixedVector() {
for (int i=0; i<n; i++) x[i] = 0;
}
template<typename C>
void copy(const C& container) {
if (container.size() != n) {
throw std::runtime_error("Wrong size");
}
int j = 0;
for (typename C::const_iterator i=container.begin(),
e=container.end();
i!=e;
++i)
{
x[j++] = *i;
}
}
};
With the above class you can declare FixedVector<int, 5> f and call f.copy(v) where v can be for example a vector or a list or anything that has size begin and end.
So FixedVector::copy is a template method and this means that the compiler will generate a different version of it for each different type you will pass to the function.
std::vector<double> y;
y.push_back(3.4); y.push_back(5.6); y.push_back(7.8);
std::list<unsigned char> z;
z.push_back('a'); z.push_back('b'); z.push_back('c');
FixedVector<int, 3> v;
v.copy(y); // This is ok
v.copy(z); // This is ok too
C++ doesn't allow template data members because this would imply a different class size depending on how many types you are using in a specific compilation unit and this doesn't go with the C++ compilation model of one-unit-at-a-time.
Adding methods is instead fine because it doesn't affect class size, and everything can be fixed at link time by avoiding pulling multiple copies of the same method from different compilation units.
You will have to declare ValTable as template
template <class T>
class ValTable{
public:
ValTable();
//template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You won't be able to do that ValTable needs to be a template
You can have this :
template <class T> //Make the class as template
class ValTable {
public:
ValTable();
template <class X>
void add(string,X);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You cannot have template member values: each translation unit could access different instantiations resulting in different ibject layouts. You'd need to factor out the type in some way.
The standard library does something along the lines of what you want for std::locale: each std::locale stores a collection of differently typed objects. It is soecial purpose and can't be used for your purpose directly.
The basic idea is to automatically map each type used to an int which is then used to map the type to an instance. The vals member would then be a function template looking up the correct instance. A rough outline could look like this:
int type_index_alloc() {
static std::atomic<int> current(0);
return ++current;
}
template <typename T>
int type_map() {
static int rc = type_index_alloc();
}
class container {
struct base { virtual ~base() {} };
template <typename T>
struct value: base { T v; };
std::map<int, std::shared_ptr<base>> vals_;
public:
T& vals() {
std::shared_ptr<base>& rc(vals_[type_map<T>()]);
if (!rc) {
rc = std::make_shared<value<T>>()); }
return static_cast<value<T>&>(*rc).v;
}
};
This a just trying to show how things are being set up: I currently don't have access to a compiler. Also, the code example just provides access to an object of type T but it could easily be changed to use a std::vector<T> instead.
I have that template class that uses a policy for it's output and another template argument to determine the type for it's data members. Furthermore the constructor takes pointers to base classes which are stored in private pointers. Functions of this objects shall take a this pointer to the template class to give them access to the data. In code this looks like this:
class ShapeGenerator;
template <typename PointData, typename OutputPolicy> class ModelCreator {
private:
OutputPolicy output;
ShapeGenerator* shape
std::vector<PointData> data;
public:
ModelCreator (ShapeGenerator *s) : shape(s) { }
void createShape() { shape->generateShape(this); }
};
ShapeGenerator is an interface and shall be implemented. It looks like this:
class ShapeGenerator {
public:
void generateShape (ModelCreator* m) = 0;
};
If I compile this with g++ 4.3.4 (cygwin) I get an error in the ShapeGenerator::generateShape saying 'ModelCreater' is not a type. I put in a forward declaration of ModelCreator but it changed nothing. I played with some combinations of types and parameters, for example passing only the vector and then I got an error message that said something about incomplete types. I guess this is the problem here.
So, is it possible to pass a templated type with without specific arguements? If so, how?
edit:
I'm not bound to the ModelCreator typename. If I have to write it more template-like this isn't problem. But I would like not to specify the types of ModelCreator in the ShapeCreator object. Is that possible?
edit2:
Ok, I guess I was a bit to optimistic with this "design". It would have been nice to just throw in some ingrediences and get a soup. But now the salt has to know about the kind of water in the pot. I'll change the templates to plain old composition. Thanks you guys.
If you want to use the ModelCreator with "free" template parameters, then you have to make ShapeGenerator a template too:
template <typename PointData, typename OutputPolicy>
class ShapeGenerator {
public:
void generateShape (ModelCreator<PointData,OutputPolicy>* m) = 0;
};
or
template <template <typename, typename> class ModelCreator>
class ShapeGenerator {
public:
void generateShape (ModelCreator* m) = 0;
};
The second version takes another template as a parameter. You would use it like this:
ShapeGenerator<ModelCreator<PointDataType,OutPutPolicyType> > shapeGenerator;
You need to make ShapeGenerate a template class as well:
template <typename PointData, typename OutputPolicy>
class ShapeGenerator;
template <typename PointData, typename OutputPolicy>
class ModelCreator {
private:
OutputPolicy output;
ShapeGenerator< PointData, OutputPolicy >* shape;
std::vector<PointData> data;
public:
ModelCreator (ShapeGenerator< PointData, OutputPolicy >* s) : shape(s) { }
void createShape();
};
template <typename PointData, typename OutputPolicy>
class ShapeGenerator {
public:
void generateShape (ModelCreator< PointData, OutputPolicy> * m) = 0;
};
template <typename PointData, typename OutputPolicy>
void ModelCreator< PointData, OutputPolicy >::createShape() { shape->generateShape(this); }