Weird C++ templating issues - c++

So basically the assignment was we had to create a doubly linked list that's templated generically instead of locked to a single data type. I've tried compiling both with gcc and msvc and both compilers are giving me roughly the same errors so I'm assuming its just my bad coding and not the quirkyness of one compiler or the other.
Currently, I'm getting errors saying that my classes in linkList.h are not a template
../linkList.h:34: error: ‘llist’ is not a template type
../linkList.h:143: error: ‘iter’ is not a template type
../josephus.cpp:14: error: ‘llist’ is not a template
../josephus.cpp:14: error: aggregate ‘llist ppl’ has incomplete type
and cannot be defined ../josephus.cpp:15: error: ‘iter’ is not a
template
linkList.h
template<typename T>
class iter
{
public:
iter()
{
position = sentin;
container = sentin->payload;
}
T get() const
{
assert(position != sentin);
return position->payload;
}
void next()
{
position = position->next;
}
void previous()
{
position = position->prev;
}
bool equals(iter itr) const
{
return position == itr.position;
}
private:
node *position;
llist *container;
};
josephus.cpp
llist<int> ppl;
iter<int> pos;
int start = static_cast<int>(argv[1]) - 1;
int end = static_cast<int>(argv[2]) - 1;
Any help in this matter is much appreciated

Your forward declaration says llist is a class:
class llist;
Then you say it is a template:
template<typename T>
class llist;
Similarly with iter.
I don't know how you could make it compilable easily. However, you can make node and iter 'inside' of llist.

There are several issues.
class A;
is not the way you forward declare a templated class.
If A has a single templated parameter you need to say:
template<typename T>
class A;
If you say that after you've already said class A; you're contradicting yourself. The next issue is simlar, friend class A; if A is templated won't work, you need to say friend class A<T>; or similar. Finally, static_cast<int>(argv[1]) will not compile (althought static_cast<int>(argv[1][0]) would, but is still not want you want). To convert a string to an integer meaningfully, you'll need to use atoi, strtol, stringstream etc.

The llist is not a class. So forward declaring it is not usefull.
template<typename T> class llist;
Trying to make the code compile is relatively simple.
You have just missed the template part of a lot of the types. Search for iter llist and node and make sure they have the appropriate on the end.
If you look at the STL it is conventinal to typedef some internal types for ease of use. You could follow the same principle.
template<typename T>
class llist
{
typedef iter<T> Iter;
typedef node<T> Node;
// The rest of the code.
};

Related

How to implement intrusive data structures in C++11?

I am porting to C++11 a C code base that makes use of a number of custom intrusive data structures.
In C, the usage patterns will typically look like this:
struct foo {
// some members
struct data_structure_node node;
};
// user code
struct *foo = NULL;
struct data_structure_node *result = find_in_data_structure(data_structure, some_key);
if (node) {
foo = container_of(result, struct data_structure_node, node);
// use foo
}
Here, container_of is implemented much like in the Linux kernel:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
As the code moves to more idiomatic C++, structures like foo typically end up becoming classes that use different access controls, virtual functions, etc. This, in turn, makes them adopt a non standard layout and causes GCC and clang to emit the following warning when container_of is used:
error: 'offsetof' within non-standard-layout type 'foo' is conditionally-supported [-Werror=invalid-offsetof]
I have been pondering how to implement a safe alternative to the container_of macro. Using a pointers to data member is the first idea that came to my mind and I'm considering replacing uses of container_of by, essentially,
template <class Parent, class Member>
Parent* my_container_of(Member *member, Member Parent::* ptr_to_member)
{
Parent *dummy_parent = nullptr;
auto *offset_of_member = reinterpret_cast<char *>(&(dummy_parent->*ptr_to_member));
auto address_of_parent = reinterpret_cast<char *>(member) - offset_of_member;
return reinterpret_cast<Parent *>(address_of_parent);
}
to get struct foo * from a struct data_structure_node *.
In particular, the use of ptr_to_member against the null dummy_parent makes me uneasy as it seems equivalent to performing arithmetic on a null pointer, which I understand is undefined behavior (C++11 Standard 5.7.5).
[...] Unless both pointers point to elements of the same array object, or one past the last element of the array object, the behavior is undefined
Boost.Instrusive uses an approach that seems roughly equivalent to my_container_of().
I'm wondering:
is my_container_of() safe?
is there a cleaner way of achieving this that I'm missing?
You can do intrusive data structures in C++ even nicer than C. The first thing is to use inheritance. So you try this:
struct List {
List *next{nullptr};
};
struct MyFoo : List {
MyFoo * get_next() const { return next; }
};
But there you get an error that next is a List* and not a MyFoo *. To fix this you can introduce templates:
template <typename T>
struct List {
T *next{nullptr};
};
struct MyFoo : List<MyFoo> {
MyFoo * get_next() const { return next; }
};
Now your intrusive list has the right type for the next. But you are limited to one intrusive list per object. So lets extend the template a bit more:
template <typename T, typename U>
struct List {
T *next{nullptr};
};
class Siblings;
class Children;
struct MyFoo : List<MyFoo, Siblings>, List<MyFoo, Children> {
using Sibling = List<MyFoo, Siblings>;
using Child = List<MyFoo, Children>;
MyFoo * get_sibling() const { return Sibling::next; }
MyFoo * get_child() const { return Child::next; }
};
Now you can inherit as many List as you want into a class and scoping the access to access the right List. No need of any offset() or container_of macros.
Note: The Siblings and Children classes are just declarations and purely there to give the List different types. They are never defined or instantiated.

Why can't my friend class access a private member?

I thought when a class declared a friend class, that friends could access the declarer's private members? This doesn't seem to be the case, or I've done something wrong. I'm trying to access "first" or "last" in OULinkedList. When I try to use "first" or "last" I get a "not declared in this scope" error.
I need access to "first" because without it my next function will never return the first value of the linked list and I'm not sure how else to do it.
For example if I just want to print out the objects in my list, the following while loop always skips the first object.
while(enumerator.hasNext()){
cout << enumerator.next();
}
Which is obviously not what I want.
#include "OULink.h"
#include "Comparator.h"
#include "OULinkedListEnumerator.h"
// OULinkedList stands for Ordered, Unique Linked List. It is a linked list that is always maintained in
// order (based on the comparator provided to it when the list is created) and that only contains unique
// items (that is, duplicates are not allowed)
template <typename T>
class OULinkedList {
template <typename F>
friend class OULinkedListEnumerator;
private:
Comparator<T>* comparator = NULL; // used to determine list order and item equality
unsigned long size = 0; // actual number of items currently in list
OULink<T>* first = NULL; // pointer to first link in list
OULink<T>* last = NULL;
template <typename T>
class OULinkedListEnumerator : public Enumerator<T>
{
private:
OULink<T>* current;
int firstNode = 0;
public:
OULinkedListEnumerator(OULink<T>* first);
bool hasNext() const;
T next();
T peek() const;
};
// Implementation goes here
template<typename T>
OULinkedListEnumerator<T>::OULinkedListEnumerator(OULink<T>* first){
this->current = first;
}
template<typename T>
bool OULinkedListEnumerator<T>::hasNext() const{
if(this->current->next != NULL){
return true;
}else{
return false;
}
}
template<typename T>
T OULinkedListEnumerator<T>::next(){
T successorNode = *this->current->next->data;
this->current = this->current->next;
return successorNode;
}
template<typename T>
T OULinkedListEnumerator<T>::peek() const{
if(current != NULL){
return *current->data;
}else{
throw new ExceptionLinkedListAccess;
}
}
The description you posted suggest that your code compiled successfully. In that case what private access problems are you talking about in your question's title? Access control in C++ is a purely compile-time concept. If your code compiled sucessfully, then it has no problems with private access.
Your class template OULinkedListEnumerator is a nested class template in OULinkedList class template. Just like any nested class, it is supposed to have full access to private members of the enclosing class template OULinkedList without any need for any friend declarations.
Just in case, when you make a friend declaration for a yet-unknown entity, the entity is assumed to be a member of the enclosing namespace scope. So your
template <typename F>
friend class OULinkedListEnumerator;
refers to a global class template ::OULinkedListEnumerator and makes it a friend. Later you declare a nested class template OULinkedList::OULinkedListEnumerator. This is a completely different class template. It is not a friend. (But it doesn't need to be, see 2).
You are not allowed to reuse template parameter names in nested template declarations. You have to change the name of the nested template parameter from T to something else. In fact, I'm surprised you managed to compile the code to the point of some alleged "access problem" without hitting this parameter naming issue first.

I need a non template solution

I have a class defined like this
class A
{
private:
map<int,vector<int>> m;
public:
vector<int> GetJsonVal(int k)
{
return m[k];
}
};
I would like to change it into something like this
template<class T>
class A
{
private:
map<int,T> m;
public:
T GetJsonVal(int k)
{
return m[k];
}
};
However, I have many other places that plainly use only type A, so if I change my class into the latter, I have to fix a lot i.e change all into A<type>, which I don't want. In those places I simply do void func(A*p) or A& r=....
So, how can I both use i.e A<float> and A anywhere I like ?
So, the easiest and most legible solution that comes to mind is a type alias:
template <typename T>
class Tool {
private:
map<int,vector<T>> m;
public:
vector<T> GetJsonVal(int k) {
return m[k];
}
};
using A = Tool<int>;
And so now the old code can continue using A, and all new code can use Tool<int> or another type alias.
You could use type-erasue, but will still need to update the code here and there... An approach could be doing something like:
class A {
map<int, boost::any> m;
template <typename T>
T valueAs(int idx);
};
A a;
a.valueAs<int>();
You would have the implementation verify that the type stored and the type retrieved are the same. Then you would probably want to go to all existing uses of A and enforce the check (or check the potential error).
That is, if you want to support mixed types inside A... if you each A can only hold a particular type, you can just make a ATmpl type with the contents in the question, and then typedef ATmpl<vector<int>> A;. At this point you would still have to fix some use cases (specifically: forward declarations)...
Use template class specialization, I would say
template <> class A<vector<int>>
{
// all your old code here
}
should work...
UPDATE
Just to be clear, there is a semantic difference between template specialization and type alias. With template specialization you could put your (true and tested and bug-for-bug compatible) code into specialization and use new and shiny (but potentially buggy code) elsewhere in new production, and later when you fill it is good enough you could remove specialization and use only new code. With type specialization it is new code everywhere right away...

C++ How can I call a template function with a template class?

I have a quick question for my program: How can I call this template function with Set, rather than int?
I have a class here called Set
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
class Set
{
public:
class Iterator;
void add(T v);
void remove(T v);
Iterator begin();
Iterator end();
private:
vector<T> data;
};
Here's my cpp:
Unfortunately, main cannot be a template function so I had to make another function addstuff, which main calls
template <class T>
Set<T> addstuff()
{
Set<T> a;
a.add(1);
a.add(2);
a.add(3);
a.add("a string");
return a;
}
void main()
{
addstuff<Set>(); //<< Error here. If I use addstuff<int>(), it would run but
//I can't add string to it. I am required to be able to add
//different data types to this vector
}
Your writing addstuff<Set>() would be an attempt to resolve to Set<Set> addstuff() which is meaningless.
addstuff<std::string>() would allow you to add std::strings to your set, but then a.add(1) would fail since the literal cannot be implicitly converted to a string type.
addstuff<int>() does work but that's a merry coincidence. add(1) has the correct type in that instance to be added to Set<int>.
You could build a class Foo that has non-explicit constructors to a string and an integer and make that your template type: addstuff<Foo>(). But I'm not convinced that's what your professor wants you to do and there are better ways of solving this (type erasure for one, but this is getting quite involved).

Struct returning function in C++ class before struct definition

I have a tree-structure class named SuperTree in my C++ program and I want it to have an instance method that returns a struct or pair which one of the attributes is a pointer to a SuperTree object.
The insert function in my SuperTree class should return a Res struct, which contains a reference to another SuperTree object and a boolean value. However, if I try to compile the code, I get the following error message:
supertree.cpp:24: error: ISO C++ forbids declaration of ‘Res’ with no type
I also can't define the Res struct before my SuperTree class because it'd would not compile either. Maybe it's some case for C++ generic types or something (which I don't know how to use yet).
So this was my attempt:
#include <cstdio>
#include <utility>
using namespace std;
class AVL {
public:
int key;
int bf;
AVL* leftChild;
AVL* rightChild;
AVL()
{
}
~AVL() {};
AVL rotateLeft();
AVL rotateRight();
Res* insert(int value);
int remove();
int size();
};
// typedef pair<AVL, bool> result;
typedef struct result {
struct AVL *avl;
bool changed;
} Res;
Notice that the pair definition is commented out, but I you guys can answer for them too I'd be glad!
So that's it, how can I have both the SuperTree class and Res struct and a Res pointer returning function in my SuperTree class?
Any help is welcome. Thanks!
In case when two classes or structs must reference each other, you need to add a forward declaration for one or the other, like this:
struct Res; // No typedef is necessary in C++
class AVL {
...
Res* insert(int value);
};
struct Res {
AVL *avl;
bool changed;
};
Note that pair<AVL*,bool> would work as well instead of Res, letting you skip the forward declaration:
class AVL {
...
std::pair<AVL*,bool> insert(int value);
};
Because neither class needs to know another's size at the time of definition, you can use forward declarations.
You can declare AVL first:
class AVL; // forward declaration
typedef struct result {
// Type size information not necessary at declaration time
// for pointer and reference members,
// so a forward declaration is enough at this point.
struct AVL *avl;
bool changed;
} Res;
class AVL {
public:
...
Res* insert(int value);
};
Or declare Res first:
struct Res; // forward declaration
class AVL {
public:
...
// Type size information is not necessary for return values
// at function declaration time, so a forward declaration
// is enough at this point.
// Note: you can even return by value here.
Res* insert(int value);
};
struct Res {
struct AVL *avl;
bool changed;
};
Note that you don't have to typedef a struct in C++ like in C, because you can use type name without "struct" keyword, so struct Res {...} and typedef struct result {...} Res should be the same, except you can't forward-declare the latter.