Suppose I'm building a linked list (the real data structure is completely different, but a linked list suffices for the question) whose nodes look like
template <typename T>
struct node
{
struct node<T> *next;
T data;
};
For my data structure, I have a lot of functions with return type struct node *, and I want the user to treat this type as opaque. In the linked list example, such a function could be for example get_next(struct node<T> *n) or insert_after(struct node<T> *x, struct node<T> *y). Only very few functions, namely those that allocate nodes or get/set their data field, need to know anything about T.
Is there a nicer way to "ignore T" and let the user interact only with something like a typedef struct node * opaque_handle for those functions that don't ever have to care about T? My gut reaction, coming from C, is just to cast to and from void*, but that doesn't sound very elegant.
Edit: CygnusX1's comment has convinced me that I'm asking for too many guarantees from the type system at the same time that I'm trying to circumvent too many of those guarantees. I will fall back to letting T be void * at the cost of casting and indirection.
While you don't care about what T is, you most like want to differenciate it from a different type - say U, don't you?
You probably want the following to raise an error:
node<T>* elem1 = ...
node<U>* elem2 = ...
elem1 = elem2
There are a few ways to make your code simpler without sacrificing the type checking or run-time perforamce:
If you use C++11, consider using auto instead of explicitly naming the type when using your functions
If node<T> is very common in your code, you can set a global-scope typedef
Also note, that in the context of node<T> definition, using a plain node (without template arguments) is allowed.
If you really want to hide the contents of the node, consider implementing the pimpl pattern as suggested by mvidelgauz.
If you can use boost, then boost::any or boost::variant may be able to help implement heterogeneous containers.
Is something like this what you're after?:
#include <iostream>
#include <boost/any.hpp>
#include <list>
using Collection = std::list<boost::any>;
using Node = Collection::iterator;
static Collection anys;
template<typename T>
Node insert_after(T const& obj, Node start_pos = anys.end())
{
return anys.insert(start_pos, boost::any(obj));
}
void print_type(boost::any const& a)
{
if (a.type() == typeid(int)) { std::cout << "int" << std::endl; }
else if (a.type() == typeid(float)) { std::cout << "float" << std::endl; }
}
int main()
{
const auto node1 = insert_after(int(1));
const auto node2 = insert_after(float(2.57));
const auto node3 = insert_after(int(3));
std::cout << boost::any_cast<int>(*node1) << std::endl;
std::cout << boost::any_cast<float>(*node2) << std::endl;
std::cout << boost::any_cast<int>(*node3) << std::endl;
print_type(*node1);
print_type(*node2);
print_type(*node3);
return 0;
}
Outputs:
1
2.57
3
int
float
int
Related
I have the below code which i am planning to use it for sum or node values of a list.
#include <iostream>
#include <string>
using namespace std;
template <typename T, typename U, T node>
struct Sum {
static const U sum = Sum<T,U,node->next>::sum + node->value;
};
template <typename T,typename U, NULL>
struct Sum {
static const U sum = {};
};
template <typename T>
struct Node {
T value;
Node* next;
Node() {
value = {};
next = NULL;
}
};
int main()
{
Node<string>* n1;
n1->value = "Hello";
Node<string>* n2;
n2->value = "World!";
n1->next = n2;
const Node<string>* const nx=static_cast<const Node<string>* const>(n1);
const string str=Sum<Node<string>*, string, nx>::sum;
return 0;
}
I get the below errors.
1>templatemetaprogramming.cpp(15):
error C2059: syntax error: 'constant'
1>templatemetaprogramming.cpp(18):
error C2976: 'Sum': too few template arguments 1>
1>templatemetaprogramming.cpp(16):
note: see declaration of 'Sum'
First one i think is because i cannot use NULL as constant to Node*
second one seems to be the same, i did cast to a constant the Node pointer. Can anyone help to fix it? Thank you
You try to compute something at compile time which is only available at runtime. In fact this is the whole point of a linked list (it is a dynamic data structure which is unknown before running the program). So the computation of it's sum definetly has to happen at compile time.
Templates are evaluated at compile time. Therefore you can only pass constant expressions to a template but no expressions that will only be known at runtime.
I am quite sure you added all the const and static_cast keywords in the following piece of code, because the compiler complained about being unable to use non-const expressions in that context or something similar:
const Node<string>* const nx=static_cast<const Node<string>* const>(n1);
const string str=Sum<Node<string>*, string, nx>::sum;
If you look at it, semantically this just doesn't make any sense. Let's say you wrote this originally (just to remove some complexity):
Node<string>* nx = new Node<string>(n1);
string str = Sum<Node<string>*, string, nx>::sum;
What will this evaluate to? Let's play preprocessor for a while (Sure a compiler is much smarter, but I am not):
The first expression will instantiate an object of the following type
struct Node {
string* value;
Node* next;
Node() {
value = {};
next = NULL;
}
};
The second line something like:
struct Sum {
static const string sum = Sum<Node<string>*, string, nx->next>::sum + nx->value;
};
What is nx in that context? This doesn't make sense, right? Again, this is not what the compiler does, but you hopefully get the idea.
I edited your code to do what you (probably) want. (Working example here)
#include <iostream>
#include <string>
using namespace std;
template <typename T>
struct Node {
T value;
Node* next;
Node() {
value = T();
next = NULL;
}
static T sum(Node<T> *node) {
T s;
Node<T> *next = node;
while(next != NULL) {
s = s + next->value;
next = next->next;
}
return s;
}
};
int main()
{
Node<string> n1 = Node<string>();
n1.value = string("Hello");
Node<string> n2 = Node<string>();
n2.value = string("World!");
n1.next = &n2;
string str = Node<string>::sum(&n1);
cout << str << endl;
return 0;
}
Note:
Besides from the things I mentioned above your code has many other issues. This for example
Node<string>* n1;
n1->value = "Hello";
will lead to undefined behavior and most likely to a segmentation fault as the content of n1 is not defined. I don't know your c++ knowledge but I think you should learn about pointers, stack, heap and so on before learining anything about templates.
What you want to achieve is impossible, you can not mix compilation time computation and runtime execution: in your case, linked list is created at runtime. But your template instantiation is done at compilation time: compiler is not able to predict how many template it has to create to run through complete list.
What you want to do has to be done with standard function, not with template. You only can use template for static data, like type, but definitively not for runtime variable. Runtime variable should be pass as a function parameter. So, you can have a function like this:
template <typename T, typename U>
U Sum(T *node)
{
// run through complete list by iteration or recursion to do sum
}
You can achieve what you want by a lot of different possible designs. Just take care that runtime data is passed as function parameter.
If you want to iterate over static data, you can use variadic template.
And in C++11 std::string is always a runtime data, it can not be used as a constant expression
So I have 2 classes, a templated class named Node<T> and a nontemplated one named Context. I have a few methods in Context that need to return any type of Node<T>.
For instance, sometimes it will need to return a Node<double> and sometimes an Node<int> etc. I also have some methods that I’d like to have that take any type of Node<T> as a parameter.
Is there any way I can do this that doesn’t include having separate methods in Context for each possible case?
class Node
{
T Val;
public:
Node(T value) : Val(val) {}
T getVal() { return Val; }
}
class Context
{
Node<type>* divide(Node<type>* LHS, Node<type>* RHS)
{
type Solution LHS->getVal() / RHS->getVal();
return new Node<type>(Solution);
}
}
For instance, here, I want to return either a Node<double> if the answer ends up being a decimal, else I want to return a Node<int>. It will return a Node<double> with the solution as Node->Val; And other times, the operation will return an Node<int> (like 4/2) so it will return a Node<int> instead. This is a cut down example of what I want to do but its the same idea.
Polymorphism as intended with virtual methods can't be achieved in C++ if you need different return types.. unless you use something like boost::any or return opaque void *.
For the way C++ works, if you need different return types you need different signatures and hence 2 different methods, however C++ has syntactic sugar for letting the compiler handling that (templates) so that the coder have just to write 1 method once.
template < typename T>
class Node{
//...
};
class Container{
public:
template< typename T>
Node< T> * getNode(){
}
};
a possible implementation:
#include <stack>
#include <string>
#include <typeinfo>
class Container{
std::stack<void *> data;
std::stack<std::string> names;
public:
//push a node on the stack (you have to allocate it)
template< typename T>
void addNode( Node< T> * p){
data.push(static_cast<void*>(p));
names.push(typeid(T).name());
}
template< typename T>
Node< T>* removeNode(){
if(names.top()==typeid(T).name()){
names.pop();
Node< T>* node = reinterpret_cast<Node<T>*>(data.top());
data.pop();
return node;
}
return NULL; //returns nullptr;
}
};
of course, this is just a working example (provided you have Node defined somewhere). To show you a possible way (literally that's the simplest example I can think of, but you can improve performance and use it to design the solution to your problem).
Usage example:
Container c;
Node<double> n1* = new Node<double>(5.0);
Node<double> n2* = new Node<double>(3.0);
Node<int> n3* = new Node<int>(100);
c.addNode(n1);
c.addNode(n2);
c.addNode(n3);
//since I used a stack now I check node in reversed order
cout<< c.getNode<double>() == n3 <<endl; // false! n3 use "int"
cout<< c.getNode<int>() == n3 <<endl; //true!
cout<< c.getNode<double>() == n2 <<endl; //true!
cout<< c.getNode<int>() == n1 <<endl; //false! n1 use double
cout<< c.getNode<double>() == n1 <<endl; //true
delete n1;
delete n2;
delete n3;
I have the following class:
typedef struct Listable
{
struct Listable *next;
struct Listable *prev;
// Lots of other class members not pertaining to the question excluded here
} Listable;
and I inherit from it like so:
typedef struct Object : Listable
{
} Object;
Problem is, when I do something like this:
Object *node;
for (node = objectHead; node; node = node->next);
I get an error with 'node = node->next', since node->next is of type Listable, while node is of type Object.
How can I use templates in the Listable base class to make the prev & next pointers change their type to the class being used?
Perhaps something like:
typedef struct Listable<T>
{
struct Listable<T> *next;
struct Listable<T> *prev;
// Lots of other class members not pertaining to the question excluded here
} Listable;
and I inherit from it like so:
typedef struct Object : Listable<Object>
{
} Object;
I have over 10 years of C, but am fairly new to C++ features like templates. So I'm not sure what syntax I should be using.
The template syntax itself is fairly straight forward:
template <typename T>
struct Listable
{
T *next;
T *prev;
// Lots of other class members not pertaining to the question excluded here
};
So, when it gets inherited by Object like this:
struct Object : Listable<Object>
{
};
Object will get the next and prev pointers.
Since Listable is managing pointers, you will need to pay attention to the Rule of Three. That is, you have to think about what needs to be done during destruction, copy construction, and assignment so that memory is managed properly.
Are you sure you would rather not just use:
Listable *node;
for (node = objectHead; node; node = node->next);
instead? That would work even if node is actually an Object, because Object inherits from Listable.
Also, as Jerry mentions, there already is a built-in templated, doubly linked list that is part of the C++ Standard Template Library. You would not need to manually write a for loop either, because you could also use std::foreach to operate on it:
#include <list>
#include <algorithm>
#include <iostream>
struct Sum {
Sum() { sum = 0; }
void operator()(int n) { sum += n; }
int sum;
};
int main()
{
std::list<int> nums{3, 4, 2, 9, 15, 267};
Sum s = std::for_each(nums.begin(), nums.end(), Sum());
std::cout << "sum: " << s.sum << '\n';
std::cout << "elements: ";
//Or, you could use iterate over each node in the list like this
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
}
You seem to be conflating the notion of of a linked list with that of a node in the linked list. Then you're adding in an Object that (supposedly) is one of these confused node/linked list things. At least to me, this sounds quite confused and confusing.
I'd prefer to see something like:
template <class T>
class linked_list {
class node {
T data;
node *next;
public:
node(T data, node *next = NULL) : data(data), next(next) {}
};
node *head;
public:
void push_back(T const &item);
void push_font(T const &item);
// etc.
};
Caveat: of course, for real code you 1) probably don't want to use a linked list at all, and 2) even if you do, it should probably be a std::list.
Suppose I want to create an unmodifiable linked-list (i.e. it can only be traversed, no nodes can be added or removed once it was initially created). This could be easily implemented by:
struct ListNode
{
int value;
ListNode* nextNode;
}
My question is .... Would it be possible to use references instead of pointers?
struct ListNodeWithRefs
{
int value;
ListNodeWithRefs &nextNode;
}
I am not sure it would provide any performance gain at all but ... this question popped up while coding and my answer so far is no but I could be missing something.
In principle, nothing prevents you from using references, and constructing list elments like this:
ListNodeWithRefs::ListNodeWithRefs(ListNodeWithRefs &next):
nextNode(next)
{}
But there is a chicken and egg problem because next also enforces its next element to exist at its creation and so on ...
Note: I think my question can also be applied to defining the list as:
struct ListNodeConst
{
int value;
const ListNode* nextNode;
}
This is typical of a cons-list in functional languages:
data List a = Empty | Node a (List a)
The trick is though, List a is a full type and can refer either to Empty OR another node (which is why it can terminate).
In order to achieve this in C++, you could take advantage of either a union (but it's not that well supported) or of polymorphism.
template <typename T>
struct ListBase {
enum class Kind { Empty, Node };
explicit ListBase(Kind k): _kind(k) {}
Kind _kind;
};
And then:
template <typename T>
struct EmptyList: ListBase<T> {
EmptyList(): ListBase<T>(Kind::Empty) {}
};
template <typename T>
struct ListNode: ListBase<T> {
ListNode(T const& t, ListBase<T>& next):
ListBase<T>(Kind::Node), _value(t), _next(next) {}
T _value;
ListBase<T>& _next;
};
And now, you don't have a chicken & egg problem any longer; just start from an instantiation of EmptyList<T>.
Note: the presence of _kind in the base class is not that OO, but it makes things closer to the functional example by tagging which alternative is used.
Take a look at this example by sbi, it seems to work: https://stackoverflow.com/a/3003607/1758762
// Beware, un-compiled code ahead!
template< typename T >
struct node;
template< typename T >
struct links {
node<T>& prev;
node<T>& next;
link(node<T>* prv, node<T>* nxt); // omitted
};
template< typename T >
struct node {
T data;
links<T> linked_nodes;
node(const T& d, node* prv, node* nxt); // omitted
};
// technically, this causes UB...
template< typename T >
void my_list<T>::link_nodes(node<T>* prev, node<T>* next)
{
node<T>* prev_prev = prev.linked_nodes.prev;
node<T>* next_next = next.linked_nodes.next;
prev.linked_nodes.~links<T>();
new (prev.linked_nodes) links<T>(prev_prev, next);
next.linked_nodes.~links<T>();
new (next.linked_nodes) links<T>(next, next_next);
}
template< typename T >
void my_list<T>::insert(node<T>* at, const T& data)
{
node<T>* prev = at;
node<T>* next = at.linked_nodes.next;
node<T>* new_node = new node<T>(data, prev, next);
link_nodes(prev, new_node);
link_nodes(new_node, next);
}
How does the list end?
You will need at least two types: the end and not. You also need lifetime management. And either runtime or static knowledge of which type.
A completely static implementation could be done, where each node is its own type that knows how far it is to the end.
Or you could just have an unintialized buffer, and create elements off it in reverse order.
A circle is also possible. Make the first reference refer to the last element you construct.
No. Reasons:
You cannot insert a node if nextNode is a reference.
What should nextNode refer to if this is list tail?
As #Vlad said, the problem with references is that you will need a final object.
The good news is that, in principle, you can still have a cyclic list, if you have a use for it.
This is a fundamental thing, if the "next" element is a non-nullable reference means that there is always a next element, that is, the list is either infinite or, more realistically, it closes on itself or into another list.
Taken the exercise further is quite interesting and strange.
Basically the only thing that seems to be possible is to defined the equivalent of the a node (which also represents the list).
template<class T>
struct node{
T value; // mutable?
node const& next;
struct circulator{
node const* impl_;
circulator& circulate(){impl_ = &(impl_->next); return *this;}
T const& operator*() const{return impl_->value;}
friend bool operator==(circulator const& c1, circulator const& c2){return c1.impl_ == c2.impl_;}
friend bool operator!=(circulator const& c1, circulator const& c2){return not(c1==c2);}
};
circulator some() const{return circulator{this};}
};
The elements have to live in the stack and the list is static (well, references are not rebindable anyway) and the links have to be const references!
Eventually the value can be made then mutable apparently (probably safe?).
(At this point one wonders how is this different from a stack array references by a modulo indices.)
There is only one way to construct the node/list object, that is to close it with itself (or with other preexising node). So the resulting list are either circular or "rho" shape.
node<int> n1{5, {6, {7, n1}}};
auto c = n1.some();
cout << "size " << sizeof(node<int>) << '\n';
do{
cout << *c << ", ";
c.circulate();
}while(c != n1.some()); //prints 5, 6, 7
I wasn't able to make a node that is not trivially constructible (aggregate?).
(Adding any sort of basic constructor produced segmentation faults for a reason I can't understand, both in gcc and clang).
I wasn't able to encapsulate the node in a "container" object for the same strange reason.
So making an object that could be constructed like this was impossible to me:
circular_list<int> l{1,2,3,4}; // couldn't do this for obscure reasons
Finally, since a proper container cannot be constructed it is not clear what is the semantics of this object, for example when two "lists" are equal? what doesn't mean to assign? or assign between list of different sizes?
It is a quite paradoxical object, with no general value or reference semantics apparently.
Any comments or improvements are welcomed!
I might be off the mark, but this works
struct Node;
struct Node {
using link = std::reference_wrapper<Node>;
Node( char data_ = 0)
: next({*this})
, data( data_ == 0 ? '?' : data_ )
{}
bool is_selfref() const noexcept {
return (this == & next.get());
}
char data;
link next;
};
The usual tests
Node A('A');
Node B('B');
Node C('C');
assert( A.is_selfref() == B.is_selfref() == C.is_selfref());
A.next = B; B.next = C;
assert(! A.is_selfref() && ! B.is_selfref() );
assert( C.is_selfref() );
assert( 'A' == A.data );
assert( 'B' == A.next.get().data );
assert( 'C' == A.next.get().next.get().data );
// C.next == C
// for those who feel safe seeing the END
Node END(127);
C.next = END;
Of course, as long as all Node's stay in the scope we are all ok here. Otherwise not. Strange and wonderful. Very limited utility?
That was quite tricky but this worked :
#include <iostream>
#include <typeinfo>
class Last {
public:
int x;
int last;
Last(int i) {
std::cout << "parent constructor(" << i << ")\n";
x = i;
last = 1;
}
};
struct fourptr {
int v1, v2;
void *p1, *p2;
};
class chain : public Last {
public:
chain(int i) : Last(i) {
std::cout << "child constructor(" << i << ")\n";
last = 0;
}
void viewandnext() {
struct fourptr *fp = (struct fourptr *) this;
std::cout << x << ", this = " << this
<< ", sizeof *this = "<< sizeof * this
<< ", * this = {" << fp->v1 << ", " << fp->v2 << ", "
<< fp->p1 << ", " << fp->p2 << "}"
<< "\n";
if (last == 0) ((chain &)next).viewandnext();
}
Last & fn(int x) {
Last * e = (x>0) ? new chain(x-1) : new Last(x-1);
return *e;
}
Last & next = fn(x); // This is not a pointer but a reference
};
int main(void) {
chain &l = *(new chain(8));
std::cout << "sizeof l = "<< sizeof l << "\n";
l.viewandnext();
}
A simple way to avoid a chicken-egg problem for a list with references is to remember that firstly your object memory is allocated, then your constructor is called. Moreover, access to this pointer is guaranteed inside of a constructor by C++ standard.
Neat way to resolve this:
struct node {
int data;
node& next;
node(node& n, int d): next(n), data(d) {}
};
node tl(tl, 69); // tl is already in the scope!
As an example, consider a simple data structure like a linked list. In C, it might look like:
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
I'd like to have the same struct and functions, but with better type checking by declaring the type of the data field, which will always be a pointer to something. An example use:
Node<Thing*> list = getListOfThings();
Thing *t = list->data;
t = getLastItem(list);
...
But I don't want to generate an implementation for every type of pointer, as happens with a normal template. In other words, I want something more like a generic or parametric type from Java, ML, and other languages. I just tried the code below as a test. The untyped C-like part would eventually go in a implementation file, while the template and function declarations would be in the header file. I'm assuming they would be optimized away and I'd be left with machine code that is about the same as the C version, except it would be type-checked.
But I'm not great with C++... Is there a way to improve this, or use more idiomatic C++, perhaps template specialization?
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
};
void *getLastItemImpl(NodeImpl *list)
{
printf("getLastItem, non-template implementation.\n");
return 0; // not implemented yet
}
template <typename T>
struct Node
{
Node<T> *next;
T data;
};
template <typename T>
T getLastItem(Node<T> *list)
{
return (T)getLastItemImpl((NodeImpl*)list);
}
struct A { };
struct B { };
int main()
{
Node<A*> *as = new Node<A*>;
A *a = getLastItem(as);
Node<B*> *bs = new Node<B*>;
B *b = getLastItem(bs);
}
This is exactly what Boost.PointerContainer does, check its implementation. Basically what it does is implement the specialization for void*, and have any other implementation forward to it static_casting the parameters in and out.
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
This is common for C, but not for C++. In C++ it usually looks like this:
template<typename T>
struct Node
{
struct Node *next;
T data;
};
T& getLastItem(const Node&);
...
Note the important difference -- the C version has another level of indirection in order to share implementations, while the C++ version need not do this. This means the C version has another n dynamic memory allocations, where n is the number of items in the list. Given that each allocation usually requires obtaining a global lock, often has at least 16 bytes of overhead per allocation, as well as all the overhead the memory manager brings to the party, the advantage of the C++ version is not insignificant, particularly when you include things like cache locality in the considerations.
Put another way, for Node<int>, the C++ version stores an int, while the C version stores an int *, along with a dynamic allocation for the int.
This of course discounting that a linked list is a horrendous data structure 90% of the time.
If you must use a linked list, and if you must use dynamic allocation for the data members, then your idea of "replace the pointers with void*s" is not unreasonable. However, if you have access to a C++11 compiler (VS2010, recent GCC versions, etc.), you should put in an assert that you depend on T being a pointer type, using std::is_pointer and static_assert, and you should use static_cast rather than C-style casts in your interface methods. The C style cast would let someone do Node<SomeTypeBiggerThanVoidPtr>, and it would compile, but explode at runtime.
As the other answers and comments said, use std::forward_list, or another existing library. If you refuse, this is more like I would do:
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
public:
// we have pointers, so fulfill the rule of three
NodeImpl() : next(NULL), data(NULL) {}
~NodeImpl() {}
NodeImpl& operator=(const NodeImpl& b) {next = b.next; data = b.data; return *this;}
// This function now a member. Also, I defined it.
void* getLastItem()
{
if (next)
return next->getLastItem();
return data;
}
void* getData() {return data;}
void setData(void* d) {data = d;}
};
// the template _inherits_ from the impl
template <typename T>
struct Node : public NodeImpl
{
Node<T> operator=(const Node<T>& b) {NodeImpl::operator=(b);}
// we "redefine" the members, but they're really just wrappers
T* getLastItem()
{ return static_cast<T*>(NodeImpl::getLastItem());}
T* getData() {return static_cast<T*>(NodeImpl::getData());}
void setData(T* d) {NodeImpl::setData(static_cast<void*>(d));}
//or, if you prefer directness...
operator T*() {return static_cast<T*>(NodeImpl::getData());}
Node<T> operator=(T* d) {NodeImpl::setData(static_cast<void*>(d));}
};
struct A { };
struct B { };
int main()
{
Node<A> as; //why were these heap allocated? The root can be on the stack
A *a = as.getLastItem();
Node<B> bs; //also, we want a each node to point to a B, not a B*
B *b = bs.getLastItem();
B* newB = new B;
bs = newB; //set the data member
newB = bs; //read the data member
}
http://ideone.com/xseYk
Keep in mind that this object doesn't encapsulate next or data really, so you have to manage all of that yourself.