I have a template class my_class<T>
which is receiving a constructor argument my_class<U>
(generally with different template parameter).
Unlike the code without templates, or with the same template parameter, I cannot access my_class<U>
instance private fields, nevertheless it's the same class.
template <class T>
class my_class {
private:
T * data;
public:
template <class U>
my_class(const my_class<U> & p) {
data = p.data; // <-- visibility exposing
}
}
Is there a trick to make it possible? Maybe I can define a friend class with a different template argument?
To answer your comment: "It should works only if U is a child of T. Is there any way to make this?".. Use traits.. That will help you determine if U derived from T..
With the below traits, the following are the allowed arguments to functions that use them:
/**
Arguments can be (is_non_class_same<T, U>::value):
T = T -> U = T for any class.
T = void* -> U = any non-class pointer.
T = int* -> U = int*. U cannot be a float*. Incompatible pointers.
T = int -> U = float
T = double -> U = float or int. Valid.. double is large enough to hold float and int.
T = int -> U = double Invalid.. double is larger than type float.. loss of precision.
T = float -> U = double Invalid.. double is larger than type float.. loss of precision.
Arguments can be (is_class_same<T, U>::value, U>::type):
T = Base* -> U = Base*.
T = Base* -> U = Derived*
T = Base -> U = Derived Invalid.. See: Slicing Problem.
**/
Example (working code): http://ideone.com/dHZhHc <-- live example..
#include <type_traits>
#include <memory>
#include <iostream>
template<typename T, typename U>
struct is_non_class_same : public std::integral_constant<bool, (!std::is_base_of<
typename std::remove_pointer<T>::type,
typename std::remove_pointer<U>::type>::value &&
std::is_convertible<U, T>::value && sizeof(T) >= sizeof(U)) ||
(std::is_class<T>::value && std::is_class<U>::value &&
!std::is_pointer<T>::value && !std::is_pointer<U>::value &&
std::is_same<T, U>::value)>
{};
template<typename T, typename U>
struct is_class_same : public std::integral_constant<bool, std::is_base_of<
typename std::remove_pointer<T>::type,
typename std::remove_pointer<U>::type>::value &&
std::is_pointer<T>::value>
{};
class Node
{
protected:
Node* previous;
Node* next;
Node() : previous(nullptr), next(nullptr) {}
template<class T, class TD>
friend class linked_ptr;
public:
virtual ~Node() {}
};
template<typename T, typename TD = typename std::remove_pointer<T>::type>
class linked_ptr : public Node
{
private:
template<class, class> friend class linked_ptr; /** Access friend level **/
T data;
public:
template<class U, typename TU = typename std::remove_pointer<U>::type, typename = typename std::enable_if<is_non_class_same<T, U>::value || is_class_same<T, U>::value, U>::type>
linked_ptr(U data) : data(data) {}
~linked_ptr();
template<class U, typename TU = typename std::remove_pointer<U>::type, typename = typename std::enable_if<is_non_class_same<T, U>::value || is_class_same<T, U>::value, U>::type>
void setData(U data)
{
this->data = data;
}
template<class U, typename TU = typename std::remove_pointer<U>::type, typename = typename std::enable_if<is_non_class_same<T, U>::value || is_class_same<T, U>::value, U>::type>
void append(U data);
};
template<typename T, typename TD>
linked_ptr<T, TD>::~linked_ptr()
{
TD(data);
delete this->next;
}
template<typename T, typename TD>
template<typename U, typename TU, class>
void linked_ptr<T, TD>::append(U data)
{
if (!this->next)
{
this->next = new linked_ptr<U>(data);
this->next->previous = this;
return;
}
Node* t = this->next;
while(t->next != nullptr)
{
t = t->next;
}
t->next = new linked_ptr<U>(data);
}
class foo
{
public:
virtual ~foo()
{
std::cout<<"destroyed foo\n";
};
virtual void print()
{
std::cout<<"foo\n";
}
};
class bar : public foo
{
public:
virtual ~bar()
{
std::cout<<"destroyed bar\n";
}
virtual void print()
{
std::cout<<"bar\n";
}
};
int main()
{
linked_ptr<foo*> list(new foo());
list.append(new bar());
list.append(new bar());
list.append(new foo());
}