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.
Related
I'm trying to create a statistics system in C++ which will allow me to associate a string with a value of an arbitrary type. Currently, I have it working with an enum that keeps track of the type and a void * that points to the object, but this requires me to make individual if statements for all of the types I want to support. I'd like to have it so that I can support any arbitrary type using some kind of template. I've created some test code that sort of works, but there are issues:
class Test {
std::type_index type;
void *value;
public:
template <typename T>
Test(T val) : type(typeid(val)) {
T *val_p = new T;
*val_p = val;
value = (void *)val;
}
Test() : type(typeid(void)) {
value = nullptr;
}
~Test() {
//no idea how I could make this work
}
template <typename T>
T get() {
if (std::type_index(typeid(T)) == type) {
T *val_p = (T *)value;
return *val_p;
} else {
throw std::bad_typeid();
}
}
};
What I have so far works, but I don't think it would be possible to implement a destructor or copy/move constructors. The whole point is I want to store this all in a single std::unordered_map, so I can't (AFAIK) just make a template class and go from there. So, is it possible to do what I'm trying to do, and if so, how would I do it?
Based on the suggestion of GManNickG, I'm going with boost::any, as it most closely resembles what I'm looking for.
I haven't yet implemented it into the code, but the basic structure will be something along the lines of:
#include <typeinfo>
#include <boost/any.hpp>
class Statistic {
boost::any value;
public:
template <typename T>
Statistic(T val) : value(val) {}
Statistic() : value() {}
template <typename T>
bool checkType() {
return typeid(T) == value.type();
}
//Will cause an exception if the type doesn't match
//Caller should check type if unsure
template <typename T>
T get() {
if (checkType<T>()) {
return boost::any_cast<T>(value);
} else {
//throw some exception
throw bad_any_cast();
}
}
}
With this, I don't need to deal with destructors or copy/move functions, since the implicit ones will call the code already implemented by the boost library.
EDIT:
Thanks to milleniumbug for pointing out boost::any already stores the std::type_info
First, I really like the pattern of lazy initialization of singletons. I use it in the following way to get different kind of data with varying value types (The example is simplified):
class A
{
template<typename T>
const T& getData() const
{
static T data;
return data;
}
}
I know that the data variable is not connected to any instances of the class and that it exists until the program ends.
But what I want now, is that each instance of the class A should hold the variables in a non-static way and still there should be the flexibility of calling .getData<bool>() or with any other data type, without the need to specify each possible data type in the class definition.
Is that possible? I have not come up with an idea to implement that.
I thought of something with a container like:
template<A*, typename T>
class DataContainer
{
T data;
}
With that one can extend the code to:
class A
{
template<typename T>
const T& getData() const
{
static DataContainer<this, T> container;
return container.data;
}
}
But that does not compile.
Does anybody of you have an idea how to implement that?
Here's one idea, using Boost.any:
#include <typeinfo>
#include <type_index>
#include <unordered_map>
#include <boost/any.hpp>
struct ThingGetter
{
template <typename T>
T & get()
{
auto key = std::type_index(typeid(T));
auto it = things.find(key);
if (it == things.end())
{
it = things.emplace(key, boost::any(T())).first;
}
return boost::any_cast<T&>(*it);
}
std::unordered_map<std::type_index, boost::any> things;
};
This simple version assumes that each type can be value-initialized and creates a value-initialized value if no entry for the requested type exists. Alternative implementations could return a pointer that might be null and have a separate insertion interface.
Usage:
ThingGetter mythings;
mythings.get<bool>() = true;
mythings.get<double>() = 1.5;
return mythings.get<int>();
I am trying to implement a memory management system to deal with pointers being stored in maps.
struct refmanager{ //since this class is only for inheritance
//and not for polymorphism their does not need to be a virtual destructor
int count;
refmanager():count(0){}
};
The first idea I had was to inherit the above struct into classes I am going to insert into maps as pointers.
template <class P> void ref(P ptr)
{
ptr->count+=1;
cout<<"increasing ref count\n";
}
template <class P> void deref(P ptr)
{
ptr->count-=1;
cout<<"decreasing ref count\n";
if (ptr->count==0)
delete ptr;
}
Than I was going to use the above template functions to increase and decrease the reference count. To make the system automatic I was going to use the template functions below as replacements for the normal map methods (note this is not complete and the clear map method was written for my test case and is not generic).
template <class M, class K, class V> void mapinsert(M &map, K key, V value)
{
ref(value);
map.insert(pair<K, V>(key, value));
}
template <class T> void clearmap(T input)
{
deref(input[1]);
input.clear();
}
From preliminary testing this idea works. But I don't have the knowledge to know if this will lead to possible disaster later. Can someone with more experience please let me know if this memory management concept is any good and if not when, where and why will it fail?
I only look at the space release of reference object (delete ptr), but where is the allocation?
You must ensure every reference objects are allocated in heap, not in stack.
value in ref(value); is a pointer? Because value is the template defined type, it may be NOT a pointer.
Apparently I cant put code in comments. Anyway this was in response to Charlies answer. By the way he is right and the method above is doable but is not the safest method. Below is a safer method.
you can produce a refmanger class with this code:
class refmanager{
private:
int count;
public:
refmanager():count(0){}
virtual ~refmanager() {}
void ref(refmanager* ptr)
{
ptr->count+=1;
}
void deref(refmanager* ptr)
{
ptr->count-=1;
if (ptr->count==0)
delete ptr;
}
};
The refmanager class can be inherited by classes which need to have their pointers reference managed.
The code below will now only compile when V and T are objects which contain the ref and deref methods with the correct format. In other words you are ensuring the code will not crash unexpectedly in the middle of running it.
template <class M, class K, class V> void mapinsert(M &map, K key, V value)
{
value->ref(value);
map.insert(pair<K, V>(key, value));
}
template <class T> void clearmap(T input)
{
input[1]->deref(input[1]);
input.clear();
}
I've a templatized class
template <typename T>
class Factors
{
public:
Factors(){};
deque<string> stringsDeck;
// some methods and variables here
map <string, string> getNext();
};
The getNext method combines a string used as key with the strings from stringsDeck used as value and returns a map <string,string>.
Provided that I have templatized stringify and string2num functions, I would like to have a method map<string,Scalar> getNext() which for every other type except from string acts converting the values of the map to the specified template type T.
The compiler doesn't let me overload two methods with the same name but with different return type, specifically:
map <string, T > getNext()
{
// converts the values of getNext() return map into the specified type T
return convertedMapWithValuesOfTypeT;
}
What can be the solution in this case? I would like to keep the name of the method the same for string and other types (basically numerical types which can be converted from string via a lexical cast)
The language doesn't allow function overloads which differ only on
return type, because in most cases, the return type isn't considered in
function overload resolution. In this case, you really have three
possible solutions:
The simplest (and therefore the preferred solution in most cases) is
just to give the two functions different names:
getNextAsMapToType and
getNextAsMapToString, for example.
Alternatively, you could declare the function a template:
template<typename U>
std::map<string, U> getNext();
then, specialize this function for std::string and
T (and for
nothing else). The user will have to specify
getNext<std::string>()
or getNext<...> to call the one he wants.
Generally, I would find this considerably less readable than the
previous solution, but it might be applicable in templates, where
the names should contain or at least suggest the name of the type.
Finally, it _is_ possible to simulate overloading on the return
type, if you don't mind some extra complexity. To do this, you still
have to implement one of the other solutions, but the client code
doesn't see it. Basically, your getNext() function must return a
proxy, with overloaded conversion functions, something like:
class Proxy
{
Factors* myOwner;
public:
Proxy( Factors& owner ) : myOwner( &owner ) {}
operator std::map<std::string, std::string>() const
{
return myOwner->getNextAsMapToString();
}
operator std::map<std::string, T>() const
{
return myOwner->getNextAsMapToType();
}
};
Proxy getNext() { return Proxy( *this ); }
Client code can then just call getNext(), and depending on what they
do with the results, either getNextAsMapToString or
getNextAsMapToType will be called.
You can add a runtime-check in getNext using [typeid]
(http://en.cppreference.com/w/cpp/language/typeid) to see if T is a string or not.
Something like:
template <typename T>
class Factors
{
public:
Factors(){};
deque<string> stringsDeck;
// some methods and variables here
map <string, T> getNext();
{
if (typeid(T) == typeid(string))
{
// Special handling for strings
}
else
{
// Do something else for other types
}
}
};
Edit
As fschoenm suggests, template specialization is probably better:
template <typename T>
class Factors
{
public:
Factors(){};
// some methods and variables here
map <string, T> getNext();
};
template <>
class Factors<string>
{
public:
Factors(){};
deque<string> stringsDeck;
// some methods and variables here
map <string, string> getNext();
};
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.
};