How do I make it so the following code is externalised outside the class:
template<typename TemplateItem>
class TestA
{
operator const int (){return 10;}
};
So it appears like:
template<typename TemplateItem>
class TestA
{
operator const int ();
};
template<>
TestA<int>::operator const int()
{
//etc etc
}
So I can specialise the function for different templated types?
Write this:
template <typename T> class TestA
{
operator const int();
};
template <typename T> TestA<T>::operator const int()
{
return 10;
}
The standard antonym of "inline" is usually "out of line", by the way. Also, I'd probably make the function const, as one usually does with conversion operators (to allow conversions from constant objects).
You can either specialize the entire class, or just the member function. For the member function only, write this:
template <> TestA<int>::operator const int() { /* ... */ }
For the entire class specialization, the syntax is this:
template <> class TestA<int>
{
operator const int();
};
TestA<int>::operator const int() { /*...*/ }
I don't think you can specialize a non-template function of a template class without specializing the whole class. Which means you have to cheat. Simplist way is to move most of the implementation to a "Base" class, (everything that the two share), and have TestA inherit from that base class, and only define the functions that need specializing.
//general base
template<typename TemplateItem>
class TestABase
{
protected:
TemplateItem data;
};
//non specialized members
template<typename TemplateItem>
class TestA: public TestABase<TemplateItem>
{
public:
operator const int ();
};
//specialized members
template<>
class TestA<int> : public TestABase<TemplateItem>
{
public:
operator const int ();
};
//implementations
template<typename TemplateItem>
TestA<TemplateItem>::operator const int()
{
return data;
}
template<>
TestA<int>::operator const int()
{
return data;
}
First off, declare and define the primary templates as follows:
template<typename T>
class TestA
{
public:
operator int() const;
};
template<typename T>
TestA<T>::operator int() const
{
return -1;
}
Regarding specialization, the C++03 standard §14.5.1.1/1 tells us that non-template member functions (and constructors!) of a class template are themselves considered function templates:
A member function of a class template may be defined outside of the class template definition in which it is declared. [Example:
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
// ...
};
declares three function templates. The subscript function might be defined like this:
template<class T> T& Array<T>::operator[](int i)
{
if (i<0 || sz<=i) error("Array: range error");
return v[i];
}
—end example]
Consequently, they can be specialized without also specializing the rest of the primary class template (unlike if you were to specialize, explicitly or partially, the class template itself):
template<>
TestA<int>::operator int() const
{
return 5;
}
template<>
TestA<double>::operator int() const
{
return 3;
}
Full demo
Related
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.
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.
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.
I wrote a class and I wanted to implement an iterator for it ( as shown in the following code ). I needed to overload a variety of operators and I faced the error mentioned below:
class BaseClass
{
virtual ~BaseClass() {}
};
template<class T>
class AbstractBaseOrgan: public BaseClass
{
public:
typedef T value;
template<class TT>
class AbstractBaseIterator:
public std::iterator<std::random_access_iterator_tag,
typename std::iterator_traits<TT>::value_type>
{
protected:
TT _M_current;
const TT&
base() const
{ return this->_M_current; }
};
protected:
value te;
};
template<typename Iter>
inline bool
operator<(const typename AbstractBaseOrgan<typename
std::iterator_traits<Iter>::value_type>::template
AbstractBaseIterator<Iter>& lhs,
const typename AbstractBaseOrgan<typename
std::iterator_traits<Iter>::value_type>::template
AbstractBaseIterator<Iter>& rhs)
{ return lhs.base() < rhs.base(); }
int main()
{
AbstractBaseOrgan<int>::AbstractBaseIterator<int*> temp;
AbstractBaseOrgan<int>::AbstractBaseIterator<int*> temp2;
int ttemp;
if(operator< (temp,temp2))
ttemp = 0;
return 0;
}
Compiling it gives me the following error:
error: no matching function for call to ‘operator<(AbstractBaseOrgan<int>::AbstractBaseIterator<int*>&, AbstractBaseOrgan<int>::AbstractBaseIterator<int*>&)’
Any idea what might cause this?
4 In most cases, the types, templates, and non-type values that are
used to compose P participate in template argument deduction. That is,
they may be used to determine the value of a template argument, and
the value so determined must be consistent with the values determined
elsewhere. In certain contexts, however, the value does not
participate in type deduction, but instead uses the values of template
arguments that were either deduced elsewhere or explicitly specified.
If a template parameter is used only in non-deduced contexts and is
not explicitly specified, template argument deduction fails.
The non-deduced contexts are:
— The nested-name-specifier of a type that was specified using a qualified-id.
You can avoid this by few ways. First way - make operator < friend for class AbstractIteratorBase, or its member.
template<class TT>
class AbstractBaseIterator:
public std::iterator<std::random_access_iterator_tag,
typename std::iterator_traits<TT>::value_type>
{
public:
template<typename Iter>
friend bool operator < (const AbstractBaseIterator<Iter>& lhs, const AbstractBaseIterator<Iter>& rhs)
{
return lhs.base() < rhs.base();
}
protected:
TT _M_current;
const TT&
base() const
{ return this->_M_current; }
};
Second variant is define AbstractBaseIterator class not in template class. And then typedef AbstractBaseIterator<T> iterator; in AbstractBaseOrgan. If you can use C++11 you can use something like this.
class BaseClass
{
virtual ~BaseClass() {}
};
template<class TT>
class AbstractBaseIterator:
public std::iterator<std::random_access_iterator_tag,
typename std::iterator_traits<TT>::value_type>
{
protected:
TT _M_current;
const TT&
base() const
{ return this->_M_current; }
};
template<typename Iter>
bool operator < (const AbstractBaseIterator<Iter>& lhs, const AbstractBaseIterator<Iter>& rhs)
{
return lhs.base() < rhs.base();
}
template<class T>
class AbstractBaseOrgan: public BaseClass
{
public:
typedef T value;
template<typename TT>
using iterator = AbstractBaseIterator<TT>;
protected:
value te;
};
int main()
{
AbstractBaseOrgan<int>::iterator<int*> temp;
AbstractBaseOrgan<int>::iterator<int*> temp2;
int ttemp;
if(operator< (temp,temp2))
ttemp = 0;
return 0;
}