Class template befriending function template - c++

I get a linker error when I try to create an executable from the following code. I get the impression I need to place a few "typenames" around or make some forward declarations; I've tried a few combinations but none worked.
template<typename T>
class enabled
{
private:
T type_;
friend const T& typeof(const enabled<T>& obj); // Offending line
};
template<typename T>
const T& typeof(const enabled<T>& obj) {
return obj.type_;
}
int main()
{
enabled<std::string> en;
std::cout << typeof(en);
std::cin.clear(), std::cin.get();
return 0;
}
1>main.obj : error LNK2001: unresolved external symbol "class std::string const& __cdecl typeof(class enabled<class std::string> const&)"

By forward declaring and specifying that the function is templated
template<typename T> class enabled;
template<typename T>
const T& typeof(const enabled<T>& obj) {
return obj.type_;
}
template<typename T>
class enabled
{
private:
T type_;
friend const T& typeof<>(const enabled<T>& obj);
};

The problem is that the function which is a friend of the class, is not a function template, while the function you actually have defined is a function template.
All that you need to do is make the friend a function template as:
template<typename T>
class enabled
{
private:
T type_;
template<typename U> //<-------------------------------note this
friend const U& typeof_(const enabled<U>& obj); //use U
};
Now this compiles just fine : http://www.ideone.com/VJnck
But it makes all instantiations of typeof_<U> friend of all instantiations of enabled<T>, which means typeof_<int> is a friend of enabled<T> for all possible value of T, and vice versa.
So a better solution is to make the function non-template and define it inside the class as:
template<typename T>
class enabled
{
private:
T type_;
friend const T& typeof_(const enabled<T>& obj)
{
return obj.type_;
}
};
Demo : http://www.ideone.com/Rd7Yk
Note that I replaced typeof with typeof_, as GCC has an extension with name typeof, and so it was giving error on ideone (as I can't turnoff extensions).

Related

Additional template arguments for friend declaration in template class?

In order for some global function
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
to be able to access to the private field value of some templated class
template<typename T>
class Obj {
public:
Obj (T value);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {}
we need to declare func<T, count> a friend of Obj<T>. But func<T, count> has to be declared before we can make it a friend of Obj<T>, and for this we need to forward-declare Obj<T>. The resulting code looks like this
// Forward declarations
template<typename T>
class Obj;
template<typename T, int count>
void func (const Obj<T>& obj);
// Obj<T>
template<typename T>
class Obj {
public:
Obj (T value);
template<int count>
friend void func<T, count> (const Obj<T>& obj);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {} // <-- ERROR
// func<T>
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
But this makes gcc complain about the "invalid use of template-id 'func' in declaration of primary template", so how do I actually declare func<T, count> a friend of Obj<T> for every count? According to this answer I just need to replace the friend declaration with this
template<typename T1, int count>
friend void func (const Obj<T1>& obj);
As far as I know this would make func<T1, count> a friend of Obj<T> regardless of whether T1 and T match, which is absurd. Is it possible to declare func<T, count> a friend of Obj<T> and no other Obj<T1>? (preferably in a way that keeps the definition of func<T, count> outside the definition of Obj<T>)
(I know I could just make count a real parameter, but the example above is just a simplification of my real code. In reality I'm trying to overload std::basic_ostream<CharT, Traits>& operator<< (std::basic_ostream<CharT, Traits>& stream, const Obj<T>& obj) for some class Obj<T> in a way that allows operator<< to access private fields of Obj<T>.)
The friend declaration must match any possible forward declaration, and of course the definition, including template arguments.
That means you need e.g.
template<typename U, int count>
friend void func(const Obj<U>& obj);
It doesn't matter if the class template argument T and the function template argument U are different, as the calls will be made to the correct function anyway.
Example:
Obj<int> int_obj;
Obj<float> float_obj;
func<X>(int_obj); // Will call void func<int, X>(int_obj)
func<X>(float_obj); // Will call void func<float, X>(float_obj)
As an alternative, you can define the function inline in the class definition, and then you don't need to provide the T or U template arguments:
template<int count>
friend void func(const Obj<T>& obj)
{
// Implementation...
}
And in neither case you should really have a forward declaration of func (as mentioned in my comment).

Fix circular dependency in arithmetic class

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.

using vector in ostream overload friend function

I have a template class called "KeyedCollection" that contains functions to insert data into a vector, as well as stream out the data. The vector is a private member function. I can't seem to figure out how to use the information from this vector in my overloading ostream friend function. Note: I cannot change the general structure of the class and the function arguments, they have to stay as they are. I list all of the class for reference, but the function in question is the last one.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include "Windows.h"
#include <string>
using namespace std;
template <class K, class T>
class KeyedCollection {
public:
// Create an empty collection
KeyedCollection();
// Return the number of objects in the collection
int size() const;
// Insert object of type T with a key of type K into the
// collection using an “ignore duplicates” policy
void insert(const K&, const T&);
// Output data value of objects in the collection,
// one data value per line
friend ostream& operator<<(ostream&,
const KeyedCollection&);
private:
// Insert required members here
int objSize;
vector<T> objects;
};
template<class K, class T>
KeyedCollection<K,T>::KeyedCollection() {
objSize = 0;
vector<T> objects;
}
template<class K, class T>
int KeyedCollection<K,T>::size() const {
objSize = objects.size();
return objSize;
}
template<class K, class T>
void KeyedCollection<K,T>::insert(const K&,const T& c) {
objects.push_back(c);
}
// !!! function i am trying to define !!!
template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {
outstream<<inst<<endl;
return outstream;
}
Also, I'm getting an error that says
"fatal error LNK1120: 1 unresolved externals"
and one that says
"error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class KeyedCollection const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$KeyedCollection#HVCustomer#####Z) referenced in function _main" ...
Just as a side question, any idea what those could be?
cppreference and Johannes Schaub - litb both provide the same method for getting this to work.
You want to make one single instance (called "specialization" in
generic terms) of that template a friend. You do it the following way
[...]
First make a forward declaration before the definition of your class:
template <class K, class T> class KeyedCollection;
template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst);
Because the compiler knows from the parameter list that the template
arguments are T and U, you don't have to put those between <...>, so
they can be left empty.
Then make your friend declaration and be sure to add <> after operator<<:
template <class K, class T>
class KeyedCollection {
public:
// snip
friend ostream& operator<< <> (ostream& outstream,const KeyedCollection<K,T>& inst);
// snip
};
Finally you can define it:
template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {
// Just an example
for (const auto& t : inst.objects)
{
std::cout << t << std::endl;
}
return outstream;
}
Live Example
Alternately, do what Yakk suggested.
template <class K, class T>
class KeyedCollection {
public:
// snip
friend ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {
for (const auto& t : inst.objects)
{
std::cout << t << std::endl;
}
return outstream;
}
// snip
};
Live Example

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.

Using STL algorithms (specifically std::sort) from within a templated class

I've declared a template class MyContainer as bellow, then created an instance of it of type DataType1. The DataType1 class provides a friend function "DataSpecificComparison" which is used by std::sort to compare DataType1 objects. The program compiled and sorted correctly.
I then defined a class called DataType2, gave it a friend implementation of "DataSpecificComparison" and used it to create another instance of MyContainer.
I am now unable to compile the program as a "C2914: 'std::sort' : cannot deduce template argument as function argument is ambiguous" compile time error is reported.
How can a developer specify that the DataSpecificComparison binary predicate is to take arguments of template type T*? Or is there another way around this issue?
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
....
public:
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison)
}
}
class DataType1
{
....
friend bool DataSpecificComparison(const DataType1 * lhs, const DataType1 * rhs)
}
class DataType2
{
....
friend bool DataSpecificComparison(const DataType2* lhs, const DataType2* rhs)
}
You can use a temporary local function pointer variable of the required type to select the correct overload of DataSpecificComparison:
void SortMyContainerObjects()
{
typedef bool (*comparer_t)(const T*, const T*);
comparer_t cmp = &DataSpecificComparison;
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), cmp);
}
Here the compiler can deduce that you want to use the DataSpecificComparison overload that matches the comparer_t type, which resolves the ambiguity.
sth already gave a correct answer, but there's also a direct alternative based on the same principle:
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(),
static_cast<bool (*comparer_t)(const T*, const T*)>(&DataSpecificComparison));
}
This uses essentially the same mechanism. The cast forces overload resolution to happen before the Template Argument Deduction for std::sort.
template<typename T>
struct DataSpecificComp : public binary_function<T, T, bool>
{
public:
bool operator()(const T* lhs, const T* rhs)
{
return *lhs < *rhs;
}
};
call the sort function as shown below:
sort(vi.begin(), vi.end(), DataSpecificComp<int>());
I'd prefer something along the following lines: by default it compares objects with less_than (so you wouldn't have to remember to provide a function with a funny name), and there's an overload that allows giving your own comparison functor (again, value-based):
#include <vector>
#include <algorithm>
#include <functional>
template <class T, class Func>
struct indirect_binary_call_type: public std::binary_function<const T*, const T*, bool>
{
Func f;
indirect_binary_call_type(Func f): f(f) {}
bool operator()(const T* a, const T* b) const
{
return f(*a, *b);
}
};
template <class T, class Func>
indirect_binary_call_type<T, Func> indirect_binary_call(Func f)
{
return indirect_binary_call_type<T, Func>(f);
}
template <class T>
class MyContainer
{
private:
std::vector<T*> m_vMyContainerObjects;
public:
void Sort()
{
Sort(std::less<T>());
}
template <class Func>
void Sort(Func f )
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), indirect_binary_call<T>(f));
}
};
int main()
{
MyContainer<int> m;
m.Sort();
m.Sort(std::greater<int>());
}
Did you try defining DataSpecificComparison as template with bunch of specializations and giving it the type?
template<T>
bool DataSpecificComparison(const T* t1, const T* t2)
{
// something non compilable here
}
template<> bool DataSpecificComparison<Data1>(const Data1* t1, const Data1* t2)
{
// return *t1 < *t2;
}
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison<T>)
}
....
Templating DataSpecificComparison should work. You can also specifically call the proper std::sort template, but it's a bit cumbersome:
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
typedef bool (*compsT)(T, T);
public:
....
void SortMyContainerObjects()
{
std::sort<std::vector<T*>::iterator, compsT>(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison);
}
}