In some courses I discover some pieces of code with constructor that have types. Thing that i thought impossible with constructor.
More specifically i don't understand this two pieces of code :
template<class T>
class ValuePtr
{
public:
template<class T> ValuePtr(ValuePtr<U> const &uPtr) :
myPtr(uPtr.get()->clone())
{}
T* get() {return myPtr;}
// ...
};
And this variation :
template<class T>
class ValuePtr
{
public:
template<class U> ValuePtr(ValuePtr<U> const &uPtr) :
myPtr(uPtr.get()->clone())
{}
T* get() {return myPtr;}
// ...
};
What i see is a copy constructor, this I understand, but why is there a type before this type of constructor and why, in the second code, the type is different ? (template and not template) ?
What is the point of these constructor ?
Related
I have a template base class which has a constructor for conversion from any other template instantiation of that class, like this:
template <class T>
class FooBase
{
public:
FooBase()
{
}
template <class U>
FooBase(const FooBase<U>& other)
{
std::cout << "FooBase<U>" << std::endl;
}
};
Notice how there is no copy constructor defined.
I then have a derived template class which does have a copy constructor, as well as the constructor used for conversion:
template <class T>
class Foo : public FooBase<T>
{
public:
Foo()
{
}
Foo(const Foo& other) :
FooBase<T>(other)
{
}
template <class U>
Foo(const Foo<U>& other) :
FooBase<T>(other)
{
}
};
Because FooBase doesn't have a copy constructor, this results in FooBase<T>(other) making a call to the compiler-generated copy constructor. Which means if I run this:
int main()
{
Foo<int> a;
Foo<int> b(a);
return 0;
}
The output is nothing, when it should be FooBase<U>.
Of course, I could try to solve the issue by creating a copy constructor in FooBase and using delegating constructors:
FooBase(const FooBase& other)
: FooBase<T>(other)
{
}
But unfortunately that doesn't work, and it would result in a recursive call as the compiler helpfully points out:
warning C4717: 'FooBase<int>::FooBase<int>': recursive on all control paths, function will cause runtime stack overflow
So the only solution would be to duplicate the logic into both constructors.
Is there any way around this that doesn't involve code duplication or a separate initialization function?
You could have a third, private constructor that both the copy constructor and the constructor template delegate to and which contains the actual work:
template <typename T> class FooBase
{
struct Tag{};
template <typename U> // May have U = T
FooBase(Tag, const FooBase<U> & rhs)
{
// actual implementation
}
public:
FooBase(const FooBase & rhs) : FooBase(Tag(), rhs) {}
template <typename U> // Never selects U = T
FooBase(const FooBase<U> & rhs) : FooBase(Tag(), rhs) {}
};
In function myfun is there a way to access rhs.var without writing a public function which returns var? Also, as I understand, this happens because rhs could be a different type... Is this correct?
#include <iostream>
template<class T>
class foo
{
private:
T var;
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs)
{
auto i = rhs.var; //BOOM
}
};
int main()
{
foo<int> a = 5;
foo<double> b = 2.2;
a.myfun(b);
}
Suggested Solutions
You could either provide a public accessor to your private member variable:
template<class T>
class foo {
T var;
public:
foo(T v) : var(v) {}
T getVar() const { return var; }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
template<class Type>
void myfun(foo<Type>& rhs) {
auto i = rhs.getVar();
^^^^^^^^
}
};
Or as already Dieter mentioned in the comments you could make your template class a friend:
template<class T>
class foo {
T var;
template <class> friend class foo;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs) {
auto i = rhs.var;
}
};
Overview
The reason why the template member function myfun is not granted access to private member variable var of class template foo is that the compiler interprets class foo<Type> and class foo<T> as completely different class types, even though they would originate from the same template class definition. Thus, as being different class types the one cannot access the private members of the other.
you can define the second type as fried like:
template<class T>
class foo
{
private:
T var;
public:
foo(T v) : var(v) {}
template<class Type>
void myfun(foo<Type>& rhs)
{
auto i = rhs.var; //BOOM
}
template<class Type>
friend class foo;
};
live example
I have a set of classes implementing the curiously recurring template pattern. However, the trick is that the base class needs to return instances of the subclasses. Here's an example:
template <typename SubType>
class ArithmeticBase
{
public:
template <typename OtherType>
const Addition operator+(const OtherType &other)
{return Addition(get_subclass(), other);}
// ...
// Operators for subtraction, multiplication, division, ...
private:
const SubType &get_subclass() const
{return *static_cast<const SubType*>(this);}
};
template <typename OperatorType1, typename OperatorType2>
class Addition : ArithmeticBase<Addition<OperatorType1, OperatorType2>>
{
public:
Addition(const OperatorType1 &op1, const OperatorType2 &op2)
: op1(op1)
, op2(op2)
{}
private:
const OperatorType1 &op1;
const OperatorType2 &op2;
};
// ...
// Additional classes for subtraction, multiplication, division, ...
Compiling this fails because the Addition class is not defined before it's used in the ArithmeticBase class:
arithmetic.cpp:6:8: error: unknown type name 'Addition'
const Addition operator+(const OtherType &other)
^
How can I resolve this?
You could forward declare Addition before the base class.
template <typename OperatorType1, typename OperatorType2>
class Addition;
template <typename SubType>
class ArithmeticBase
{
...
};
This allows the compiler to know there is a type Addition that exists before it is defined.
Or use non-member form declared after Addition:
template <typename OperatorType1, typename OperatorType2>
class Addition;
template <typename SubType>
class ArithmeticBase
{
public:
template <typename OneType, typename OtherType>
friend const Addition<OneType, OtherType> operator+(const ArithmeticBase<OneType>& one, const OtherType &other);
private:
const SubType &get_subclass() const
{
return *static_cast<const SubType*>(this);
}
};
class ArithmeticType : public ArithmeticBase < ArithmeticType > {};
template <typename OperatorType1, typename OperatorType2>
class Addition : ArithmeticBase<Addition<OperatorType1, OperatorType2>>
{
public:
Addition(const OperatorType1 &op1, const OperatorType2 &op2)
: op1(op1)
, op2(op2)
{}
private:
const OperatorType1 &op1;
const OperatorType2 &op2;
};
template <typename OneType, typename OtherType>
const Addition<OneType, OtherType> operator+(const ArithmeticBase<OneType>& one, const OtherType &other)
{
return Addition<OneType, OtherType>(one.get_subclass(), other);
}
int main()
{
ArithmeticType a, b;
a + b;
}
In addition to forward declaring the Addition class (as bhzag's answer shows) you'll need to move the definition of operator+ to after the definition the Addition class. Otherwise you'll get an error on the next line.
Make sure the definition is in the header file. If it isn't, you'll get linker errors.
I'm trying to implement boost::any like class:
struct any
{
private:
struct holderBase
{
virtual ~holderBase(){}
};
template<typename T>
struct holder : public holderBase
{
T content;
holder(const T& value) : content(value){}
holder(const holder<T>& other) : content(other.content){}
};
holderBase *hl;
public:
template<typename T>
any(const T& data = T()) { hl = new holder<T>(data); }
any(const any& other) { hl = other.hl; }
template<typename T>
T get()
{
if(holder<T>* p_hl = dynamic_cast<holder<T>*>(hl))
return p_hl->content;
else
throw std::runtime_error("std::runtime_error");
}
};
I use a holder class (inherited by holderBase) to store the data.
How can I modify the any::get() function (or even modify the whole code) so that it doesn't need a template parameter (the get() function)?
You could do it like this:
template<typename T>
T get(T *ptr);
Similar to the C time function, you would return the result, as well as store it in ptr.
Edit: You could also override the casting operator:
template<typename T>
operator T()
{
return get<T>();
}
Which will implicitly do what you want.
Stating the obvious: If you don't want to return 1 particular type to the user then it needs to be templated. There's nothing you can do about it.
I have a class with one std::unique_ptr as class member. I was wondering, how to correctly define the copy constructor, since I'm getting the following compiler error message: error C2248: std::unique_ptr<_Ty>::unique_ptr : cannot access private member declared in class 'std::unique_ptr<_Ty>. My class design looks something like:
template <typename T>
class Foo{
public:
Foo(){};
Foo( Bar<T> *, int );
Foo( const Foo<T> & );
~Foo(){};
void swap( Foo<T> & );
Foo<T> operator = ( Foo<T> );
private:
std::unique_ptr<Bar> m_ptrBar;
int m_Param1;
};
template < typename T >
Foo<T>::Foo( const Foo<T> & refFoo )
:m_ptrBar(refFoo.m_ptrBar),
m_Param1(refFoo.m_Param1)
{
// error here!
}
template < typename T >
void Foo<T>::swap( Foo<T> & refFoo ){
using std::swap;
swap(m_ptrBar, refFoo.m_ptrBar);
swap(m_Param1, refFoo.m_Param1);
}
template < typename T >
Foo<T> Foo<T>::operator = ( Foo<T> Elem ){
Elem.swap(*this);
return (*this);
}
Assuming the goal is to copy-construct the uniquely-owned Bar,
template < typename T >
Foo<T>::Foo( const Foo<T> & refFoo )
: m_ptrBar(refFoo.m_ptrBar ? new Bar(*refFoo.m_ptrBar) : nullptr),
m_Param1(refFoo.m_Param1)
{
}
Unique_ptr documentation:
Stores a pointer to an owned object. The object is owned by no other unique_ptr.
The object is destroyed when the unique_ptr is destroyed.
You cant copy it because two objects can't own it.
Try switching to a std::shared_ptr.
EDIT I should point out that this would make both objects have a pointer to that same object. If you want to copy the uniquely owned object Cubbi's solution is the correct one.
A possibility is to create a new clone_ptr type for this.
Below is a rudimentary example of a clone_ptr that invokes the correct copy constructor (and destructor) of a derived object. This is done here by creating a "type erasure" helper when the clone_ptr is created.
Other implementations may be found on the Internet.
#include <memory>
namespace clone_ptr_detail
{
template <class T>
class clone_ptr_helper_base
{
public:
virtual ~clone_ptr_helper_base() {}
virtual T* clone(const T* source) const = 0;
virtual void destroy(const T* p) const = 0;
};
template <class T, class U>
class clone_ptr_helper: public clone_ptr_helper_base<T>
{
public:
virtual T* clone(const T* source) const
{
return new U(static_cast<const U&>(*source));
}
virtual void destroy(const T* p) const
{
delete static_cast<const U*>(p);
}
};
}
template <class T>
class clone_ptr
{
T* ptr;
std::shared_ptr<clone_ptr_detail::clone_ptr_helper_base<T>> ptr_helper;
public:
template <class U>
explicit clone_ptr(U* p): ptr(p), ptr_helper(new clone_ptr_detail::clone_ptr_helper<T, U>()) {}
clone_ptr(const clone_ptr& other): ptr(other.ptr_helper->clone(other.ptr)), ptr_helper(other.ptr_helper) {}
clone_ptr& operator=(clone_ptr rhv)
{
swap(rhv);
return *this;
}
~clone_ptr()
{
ptr_helper->destroy(ptr);
}
T* get() const { /*error checking here*/ return ptr; }
T& operator* () const { return *get(); }
T* operator-> () const { return get(); }
void swap(clone_ptr& other)
{
std::swap(ptr, other.ptr);
ptr_helper.swap(other.ptr_helper);
}
};
See usage example: http://ideone.com/LnWa3
(But perhaps you don't really need to copy your objects, and might rather explore the possibilities of move semantics. For example, you can have a vector<unique_ptr<T>>, as long as you don't use functions that copy the contents.)