C++ template class syntax - c++

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.

Related

How works template constructors?

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 ?

Calling base class template constructor in C++

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) {}
};

C++ Template - In-class Struct

For the following code, I got a compilation error at implementation line as:
"B does not define a type".
I am aware of solution of put the function definition inside of class declaration. Is it possible, though, to have the function definition out of the template class declaration? Thanks
template<typename T>
class A {
public:
// ctor, dtor and interface funcs etc
private:
struct B {
T value;
B *next;
}
B *locate(const T& val) const;
// blah blah
};
template<typename T>
B *A<T>::locate(const T& val) const
{
//logic
}
Since B is defined inside A you should qualify it with A<T>:::
template<typename T>
typename A<T>::B *A<T>::locate(const T& val) const
{
//logic
}
Also note typename which is required because B is a dependent name.

C++: Making a template operator= overload a friend

So I have a templated vektor class
template<t>
class vektor
{
...
}
and I want to be able to write
vektor<int> x;
vektor<float> y;
...
y = x;
so I modify the class
template<t>
class vektor
{
template<typename U>
vektor<T>& operator=(const vektor<U> &r) {
....
}
...
}
And I'd like this function to be friend with r; that is, I want to be able to access the private members of r. Since operator= is special I can't overload operator= as a non-member function and friend it as I might normally do and friend declarations of say
template<typename U> friend vektor<U>& operator=(const vektor<T> &r);
also return "must be a nonstatic member function"
Is there a way to confer friendship in this example?
There are two quick solutions for this problem (both of them are not ideal).
Suppose that the class with very interesting name vektor looks like this (it is only an example which should illustrate the following code):
template<typename T>
class vektor
{
T data;
public:
vektor(T otherData) :
data(otherData)
{
}
T GetData() const
{
return data;
}
// ...
};
Both of solutions can be tested on the following example of code:
vektor<int> x(1);
vektor<float> y(2.0f);
y = x;
std::cout << "x.data = " << x.GetData() << std::endl;
std::cout << "y.data = " << y.GetData() << std::endl;
First solution: auxiliary friend function template
In this solution an auxiliary friend function Copy is used to execute all copy operations and is called from copy assignment operator:
template<typename T>
class vektor
{
// ...
public:
// ...
template<typename U>
vektor<T>& operator=(const vektor<U>& r)
{
return Copy(*this, r);
}
template<typename V, typename U>
friend vektor<V>& Copy(vektor<V>& l, const vektor<U>& r);
};
template<typename V, typename U>
vektor<V>& Copy(vektor<V>& l, const vektor<U>& r)
{
l.data = static_cast<V>(r.data);
return l;
}
Second solution: friend class template
Second solution is to make all vektor class template instantiations friends to each other:
template<typename T>
class vektor
{
// ...
public:
// ...
template<typename U>
vektor<T>& operator=(const vektor<U>& r)
{
data = static_cast<T>(r.data);
return *this;
}
template<typename U>
friend class vektor;
};

Using-like statement for template specialization

Suppose there is the following definition in a header
namespace someNamespace {
template<class T, class S>
int operator + (const T & t, const S & s) {
return specialAdd (t, s);
}
}
Now I would like the user of the header to be able to do something like
using someNamespace::operator + <OneClass,SecondClass>;
which is obviously not possible.
The reason for this is that I do not want my operator + interfere with the standard operator + and therefore give the user the possibility to specify for which types operator + should be defined. Is there a way to achieve this?
Use the barton-nackman trick: http://en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trick
template<typename T,typename S>
class AddEnabled{
friend int operator + (T const& t, const S & s) {
T temp(t);
return temp.add(s);
}
};
class MyClass: public AddEnabled<MyClass,int>{
public:
MyClass(int val):mVal(val){
}
int add(int s){
mVal+=s;
return mVal;
}
private:
int mVal;
};
Here another example to overload the << operator:
template<typename T>
class OutEnabled {
public:
friend std::ostream& operator<<(std::ostream& out, T const& val) {
return static_cast<OutEnabled<T> const&>(val).ioprint(out);
}
protected:
template<typename U>
U& ioprint(U& out) const {
return static_cast<T const*>(this)->print(out);
}
};
To use it you can either let your class inherit from OutEnabled:
class MyClass: public OutEnabled<MyClass>{ ...
or you can define a sentry object e.g. in an anonymous namespace in a cpp file
namespace{
OutEnabled<MyClass> sentry;
}
As soon as the template OutEnabled gets instantiated (OutEnabled<MyClass>) the GLOBAL operator std::ostream& operator<<(std::ostream& out, MyClass const& val)
exists.
Further MyClass must contain a function (template) matching
template<typename U>
U& print(U& out) const {
out << mBottomLeft << "\t"<< mW << "\t"<< mH;
return out;
}
Since this is called by ioprint.
The function U& ioprint(U& out) is not absolutely necessary but it gives you a better error message if you do not have defined print in MyClass.
A type traits class that they can specialize, and enable_if in the operator+? Put the operator+ in the global namespace, but it returns
std::enable_if< for::bar<c1>::value && for::bar<c2>::value, int >
Where bar is a template type traits class in namespace for like this:
template<class T>
struct bar: std::false_type {};
I think that should cause sfinae to make your template plus only match stuff you specialize bar to accept.
You might want to throw some deconst and ref stripping into that enable_if, and do some perfect forwarding in your operator+ as well.