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) {}
};
Related
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 ?
I have a template class with a single bool template parameter. I want to be able to implicitly convert from instantiations with the parameter equal to true, to those where it is equal to false.
I tried doing this (for the copy constructor), but the problem is that when I have Foo<true>, there are now two versions of the same constructor (with the same signature).
template <bool B>
class Foo
{
public:
Foo(const Foo& other);
Foo(const Foo<true>& other);
};
Not sure how to implement this? I also intend to have similar code for a move constructor and assignment.
You can apply SFINAE, to make Foo(const Foo<true>& other) only valid with Foo<false>.
template <bool B>
class Foo
{
public:
Foo(const Foo& other);
template <bool b = B, std::enable_if_t<!b>* = nullptr> // when b is false
Foo(const Foo<true>& other);
};
Since C++20, you'll be able to write something like this:
template<bool B>
class Foo
{
public:
Foo(const Foo& other)
: Foo(other, Tag{}) { }
Foo(const Foo<true>& other)
requires(!B)
: Foo(other, Tag{}) { }
private:
struct Tag {};
template<bool B1>
Foo(const Foo<B1>& other, Tag) {
// ...
}
};
Here the requires-clause is used instead of SFINAE (see songyuanyao's answer). The private constructor with Tag parameter can be used to avoid code duplication. You might also need to make Foo<true> a friend of Foo<false>.
There is no need for using enable_if if you need to distinguish between Foo<false> and Foo<true>. The following should work:
template <bool B>
class Foo
{
public:
Foo(const Foo<true>& other);
Foo(const Foo<false>& other);
// ...
};
https://godbolt.org/z/_9NNhR
Following the comment, to forbid conversion from false to true the following code would to the work:
template <bool B>
class Foo
{
public:
template<bool Other>
Foo(const Foo<Other>& other) {}
Foo() {}
};
template <>
template <>
Foo<true>::Foo(const Foo<false>&) = delete;
https://godbolt.org/z/NjghXK
If we want to replace the copy ctor and avoid conversion from false to true:
template <bool B>
class Foo
{
public:
Foo(const Foo<true>& other) {
std::cout << true << " set to " << B << std::endl;
}
Foo(const Foo<false>& other) {
std::cout << false << " set to " << B << std::endl;
}
Foo() {}
};
template <>
Foo<true>::Foo(const Foo<false>&) = delete;
https://godbolt.org/z/zt8VMb
In my class, we are studying C++98 so I'm trying to find the proper syntax.
How should one write the declaration:
template <class T>
class A{
public:
A();
A(const A &rhs);
A &operator=(const A &rhs);
};
Or should it be like this:
template <class T>
class A{
public:
A();
A(const A<T> &rhs);
A &operator=(const A<T> &rhs);
};
I guess the implementation is the same for both of them.
Are they different from one to another?
Given
template <class T> class A { ... };
The names A<T> and A are both valid names to refer to A<T> in the scope of the class. Most prefer to use the simpler form, A, but you may use A<T>.
While R Sahu's answer is correct, I think it's good to illustrate the case where A is not the same as A<T>, particularly where there are more than 1 instantiated template argument.
For example, when writing a copy constructor for a templated class with two template arguments, because the order of the arguments matters, you need to explicitly write out the templated types for the overloads.
Here is an example with a "Key/Value" type class:
#include <iostream>
// Has overloads for same class, different template order
template <class Key, class Value>
struct KV_Pair {
Key key;
Value value;
// Correct order
KV_Pair(Key key, Value value) :
key(key),
value(value) {}
// Automatically correcting to correct order
KV_Pair(Value value, Key key) :
key(key),
value(value) {}
// Copy constructor from class with right template order
KV_Pair(KV_Pair<Value, Key>& vk_pair) :
key(vk_pair.value),
value(vk_pair.key) {}
// Copy constructor from class with "wrong" template order
KV_Pair(KV_Pair<Key, Value>& vk_pair) :
key(vk_pair.key),
value(vk_pair.value) {}
};
template <class Key, class Value>
std::ostream& operator<<(std::ostream& lhs, KV_Pair<Key, Value>& rhs) {
lhs << rhs.key << ' ' << rhs.value;
return lhs;
}
int main() {
// Original order
KV_Pair<int, double> kv_pair(1, 3.14);
std::cout << kv_pair << std::endl;
// Automatically type matches for the reversed order
KV_Pair<double, int> reversed_order_pair(kv_pair);
std::cout << reversed_order_pair << std::endl;
}
See it live on Coliru.
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
Given the following simple C++ class:
using namespace std;
template<class T1>
class ValueWrapper {
private:
T1 value_;
public:
ValueWrapper() {}
ValueWrapper(const T1& value) {
value_ = value;
}
ValueWrapper(const ValueWrapper<T1> &wrapper) {
value_ = wrapper.value_;
}
ValueWrapper& Set(const T1& value) {
value_ = value;
return *this;
}
T1 Get() const {
return value_;
}
};
I was trying to create a simple shared_ptr wrapper for that class (ultimately allowing the developer to use the class without the dereferencing operator if desired). While I've seen a few examples of wrapping a shared_ptr, I couldn't find any that also used a specialization for a templated class.
Using the class above, I created a ValueShared class which derives from shared_ptr:
template<class T1>
class ValueShared : public shared_ptr<T1> {
public:
ValueShared& operator =(const T1& rhs) {
// nothing to do in base
return *this;
}
};
Then, I created a custom make_shared_value function:
//
// TEMPLATE FUNCTION make_shared
template<class T1, class... Types> inline
ValueShared<T1> make_shared_value(Types&&... Arguments)
{ // make a shared_ptr
_Ref_count_obj<T1> *_Rx = new _Ref_count_obj<T1>(_STD forward<Types>(Arguments)...);
ValueShared<T1> _Ret;
_Ret._Resetp0(_Rx->_Getptr(), _Rx);
return (_Ret);
}
But, here's the problem code:
template<class T1, class ValueWrapper<T1>>
class ValueShared<ValueWrapper<T1>> : public shared_ptr<ValueWrapper<T1>>{
public:
ValueShared& operator =(const ValueWrapper<T1>& rhs) {
auto self = this->get();
self.Set(rhs->Get());
return *this;
}
};
I wanted to provide a specialization of the equals operator here that was specialized to the ValueWrapper class (so that it would Get/Set the value from the right hand side value).
I've tried a few things, but the current error is:
error C2943: 'ValueWrapper<T1>' : template-class-id redefined
as a type argument of a template
Maybe this isn't the proper approach, or maybe it's not possible?
Following should remove your error:
template<class T1>
class ValueShared<ValueWrapper<T1>> : public shared_ptr<ValueWrapper<T1>> {
public:
ValueShared& operator =(const ValueWrapper<T1>& rhs)
{
auto self = this->get();
self->Set(rhs.Get());
return *this;
}
};