I have two classes (ClassA and ClassB) who both have two methods (compare and converge). These methods work exactly the same way, but these classes are not related polymorphically (for good reason). I would like to define a function template that both of these classes can explicitly instantiate as a member but I'm getting errors because the methods use "this" and when I turn them into a template the compiler throws an error because they're not member functions.
Is this impossible because of that limitation? Or is there some way to use "this" inside of a function template that is not declared as part of a template class. I've done some research and found nothing.
Logic.h
template <class T>
T* compare(const T& t) {
//stuff involving this
}
template <class T>
T* converge(const T& t,bool b) {
//other stuff involving this
}
ClassA.cpp
#include "ClassA.h"
#include "Logic.h"
//constructors
template ClassA* ClassA::compare(const ClassA& t) const;
template ClassA* ClassA::converge(const ClassA& t,bool b) const;
//other methods
classB is similar.
Any help is appreciated!
I believe you can use CRTP here. Here is an example, you can omit the friend declaration in case you can do the compare using only public members:
template<class T>
class comparer
{
public:
T* compare(const T& t)
{
//Use this pointer
bool b = static_cast<T*>(this)->m_b == t.m_b;
return NULL;
}
};
class A : public comparer<A>
{
public:
friend class comparer<A>;
A() : m_b(0)
{
}
private:
int m_b;
};
class B : public comparer<B>
{
public:
friend class comparer<B>;
B() : m_b(0)
{
}
private:
int m_b;
};
int main()
{
A a1,a2;
A* p = a1.compare(a2);
B b1,b2;
B* p1 = b1.compare(b2);
return 0;
}
You can't use this inside non-member function. What you can do is create template function and declare it as a friend of your classA and classB. But classA and classB members that are accessed by template function must have the same names.
template <typename T>
bool compare(const T& t1, const T& t2)
{
return t1.val == t2.val;
}
class A
{
public:
template <typename T>
friend bool compare(const T&, const T&);
bool compare(const A& a)
{
return ::compare(*this, a);
}
private:
int val;
};
A a1, a2;
a1.compare(a2);
What you want is impossible. Member functions must be declared and defined as members. The same goes for member function templates, from which member functions can be instantiated.
But (why) do those functions have to be members? If those functions don't need access to private stuff in these classes, make them free function templates. The whole STL (which, BTW, is but one part of the C++ standard library) is build around non-member functions and achieves a much higher level of abstraction as any OO container lib coming before it ever did.
Contrary to popular believe, non-member functions generally increase encapsulation:
If you're writing a function that can be implemented as either a member or as a non-friend non-member, you should prefer to implement it as a non-member function. That decision increases class encapsulation. When you think encapsulation, you should think non-member functions.
Related
I would like to combine the concepts of polymorphism and friendship. I am making a pure virtual member function of a base class a friend of another class. I would then like to override this pure virtual member function in the classes derived from that base class, and access private member data of the class who has such function as friend. See the code snippet below. The compiler complains when I refer to my_int in the derived classes member function add(). I understand friendship is a 1-to-1 relationship, but I wonder if there is any way around it so as to implement polymorphism. Do I just have to make the member functions of the different derived classes friends of the foo() class?
class foo {
private:
int my_int{};
public:
friend virtual int base::add();
};
class base {
public:
virtual int add() = 0;
};
class derived_1 : public base {
public:
int add() {
return my_int + 1;
}
};
class derived_2 : public base {
public:
int add() {
return my_int + 2;
}
}
First, with what you've displayed it's not going to work because my_int is a member of foo but in the base class tree there is no 'foo' to get the member from.
The easy answer would be to make the function take an int argument and do away with the use of friend entirely.
struct derived2 : base
{
int add(int arg) { return arg + 2; }
};
The use of 'friend' should make you seriously question whether what you are doing is a good answer, sometimes the answer to that question is 'yes' but not often. And the more friends you need the less often the answer remains 'yes'.
Another way would be to add a function to base:
int get_arg(foo & f) { return f.my_int; }
and make that function the friend rather than add, get_arg() would be called from each derived's add() in order to get the value to work with but get_arg is not itself virtual.
You might want to look here:
https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Friend_Function
Intent
Simulate a virtual friend function.
Solution and Sample Code
Virtual friend function idiom makes use of an extra indirection to
achieve the desired effect of dynamic binding for friend functions. In
this idiom, usually there is only one function that is a friend of the
base class of the hierarchy and the friend function simply delegates
the work to a helper member function that is virtual. The helper
function is overridden in every derived class, which does the real job
and the friend function just serves as a facade.
class Base {
public:
friend ostream& operator << (ostream& o, const Base& b);
// ...
protected:
virtual void print(ostream& o) const
{ ... }
};
/* make sure to put this function into the header file */
inline std::ostream& operator<< (std::ostream& o, const Base& b)
{
b.print(o); // delegate the work to a polymorphic member function.
return o;
}
class Derived : public Base {
protected:
virtual void print(ostream& o) const
{ ... }
};
Couple of questions/issues:
The code below isn't compiling (see comments below)
Would I have to override the hash function for Bar and Baz too if I wanted them to return id() as their hash value?
#include <functional>
class Foo
{
public:
Foo(short id);
short id() const;
private:
const short id_;
};
class Bar : public Foo {};
class Baz : public Foo {};
Foo::Foo(short id) :
id_(id)
{}
short Foo::id() const
{
return id_;
}
namespace std
{
template <> struct hash<Foo> //hash is not a class template
{ //explicit specialization of non-template std::hash
size_t operator()(const Foo& foo) const
{
return hash<short>()(foo.id()); //std::hash is not a template
}
};
}
The problem is a const reference is being passed to hash::operator() but Foo::id() is not declared const. This prevents you from calling id() on any const instance of Foo. To fix this just declare the function const like so
class Foo
{
public:
short id() const;
};
If you are defining an instance of std::hash and passing one of the derived classes as the template argument you will need to provide a specialization for each one. If you are simply passing an instance of a derived class to std::hash<Foo> you do not need to provide specializations for them.
Also make sure you are using a C++11 compiler (with C++11 mode enabled if necessary) and are including the <functional> header as mentioned by Kerrek in the comments.
template <typename T>
class Container
{
private:
T data;
public:
Container(T newData) : data(newData) {}
T getData() {return data;}
};
int main()
{
Container* numContainer=new Container<int>(5);
//Do something with numContainer
delete numContainer;
}
This doesn't compile since the type of the Container pointer must be specified, such as int.
This can, as I found out after some quick googling, be dealt with by creating a ContainerBase class which is not a template and let Container derive from it. Letting the pointer be of type ContainerBase will however not let me use methods such as getData() since it returns type T and can therefore not be declared in the ContainerBase class.
Can I somehow have a pointer which can point to an instance of a template class of any type, even if the class contains methods such as in the example above?
Can I somehow have a pointer which can point to an instance of a template class of any type, even if the class contains methods such as in the example above?
No you can't, for your template class to be instantiated the compiler must know the type of T. Think of a class template as a blueprint of a class and not as a concrete definition of a class. For every type you specify for your template class (e.g., Container<int>) the compiler generates a separate definition. The compiler when it sees the name of your template class (e.g., Container) can't deduce its type out of thin air.
IMHO, The best you can do in order to avoid explicitly specifying every time the type of the template is to use aliases like the example below:
template <typename T>
class Container {
T data;
public:
Container(T const &newData) : data(newData) {}
T getData() const {return data;}
};
using iContainer = Container<int>;
int main() {
iContainer* numContainer=new iContainer(5);
//Do something with numContainer
delete numContainer;
}
Or use runtime polymorphism as you've already mentioned in combination with use of dynamic_cast like the example below:
class BaseContainer {
public:
virtual ~BaseContainer() {}
};
template <typename T>
class Container : public BaseContainer {
T data;
public:
Container(T const &newData) : data(newData) {}
T getData() const {return data;}
};
int main() {
BaseContainer *numContainer = new Container<int>(5);
Container<int> *ptr = dynamic_cast<Container<int>*>(numContainer);
if(ptr) std::cout << ptr->getData() << std::endl;;
delete numContainer;
}
LIVE DEMO
So yeah, you can't have a template virtual class member function. That makes sense, not trying to figure that part out...and I'm trying like the devil to avoid multiple/virtual inheritance.
I've got a a template class A, and an abstract template class B that inherits from A, and a C that inherits from B.
template <typename T>
class A
{
protected:
T val;
public:
A(T a) {val = a;}
T val() {return val();}
template <typename J>
A<J> cast_as() { return A<J>((J)val); }
};
template <typename T>
class B : public A<T>
{
protected:
int b;
public:
B(T a) : A(a){b=10*a;}
virtual foo() = 0;
//and I'd like, but this can't exist
//template <typename J>
//B<J>* BCastAs();
};
template <typename T>
class C : public B<T>
{
protected:
int c;
public:
C(T c) : B(c) { c=c+1;}
virtual foo() override { cout << (a+b+c);}
};
int main() { C<int> c(10); B<double>* b = c.BCastAs<double>();}
And I can't think of any way to do that...It feels like it should be possible, as B* does not need to actually know that it is a C (much like the return of a clone call) but i don't know a way to get the c to move over correctly without having virtual template member functions, which is impossible.
The sample code you've posted looks like a having a serious design flaw to me at first glimpse.
Usually it's not necessary to have virtual functions in class templates, because you can use a CRT pattern to avoid them.
You make up the intention that you require inherited classes (this is how you make a template 'abstract'), that implement a defined interface. The interface may or (preferably) not be defined as pure virtual methods (a static interface check would do as well and cause less mysterious compiler error messages in case of missing method implementations).
You can see a sample of such template framework and how to use this technique in my STTCL template library.
In short: Use static polymorphism.
UPDATE:
And yes, I'm also using pure virtual methods in STTCL, but in a completely different manner (just as basic entry points to couple complete sets of inheritance hierarchies).
Have a base class A, and a derived class B which overrides function template Func:
class A
{
A() {...};
~A() {};
template <class T>
void Func(const String &sInput, T &tResult)
{...}
};
class B : public A
{
B() {...}
~B() {};
template <class T>
void Func(const String &sInput, T &tResult)
{...}
};
(Note that Func is non-virtual, given the lack of support in C++ for templated virtual functions.)
Now have a mainprog API, class M:
class M
{
M(boost::shared_ptr<A> &pInterfaceInput): pInterface(pInterfaceInput)
{}
template <class T>
Evaluate(const String &sInput, T &tResult)
{
pInterface->Func<T>(sInput, tResult);
}
private:
const boost::shared_ptr<A> pInterface;
};
I want the function Evaluate here to support calls to functions on base class A or any of its derived classes (such as B). This class was written with polymorphism in mind before I re-designed class A and B to have templated functions.
Now the problem here is that if I pass a shared pointer of the base type to the derived type then Func of the base class will be called, not the derived class being pointed to.
How do I get around the lack of dynamic polymorphism here?
I've considered making class M a class template on the shared pointer type and having a static_cast in the constructor to ensure this type is of the base class type (A) or of a derived class.
What's the nicest way to do this? I'd prefer not to modify classes A and B to get around this problem but all suggestions are welcome.
Thanks.
Sounds like a double dispatch problem. Perhaps this would be a good place to implement the visitor pattern?
For example, create a class Evaluator, and for each T a subclass ConcreteEvaluator<T>. Give A and B methods that visit the Evaluator. Something like:
class Evaluator
{
virtual void visit_A(A* object);
virtual void visit_B(B* object);
};
template <typename T>
class ConcreteEvaluator : public Evaluator
{
public:
String* input_reference;
T& result_reference;
ConcreteEvaluator(String& input_reference_,T& result_reference_) :
input_reference(input_reference_),
result_reference(result_reference_) {}
virtual void visit_A(A* object) {
object->Func(input_reference,result_reference);
}
virtual void visit_B(B* object) {
object->Func(input_reference,result_reference);
}
}
class A
{
...
virtual void apply_evaluator(Evaluator *eval) {eval->visit_A(this);}
...
}
class B
{
...
virtual void apply_evaluator(Evaluator *eval) {eval->visit_B(this);}
...
}
For each subclass of A, a new method must be added to ConcreteEvaluator, so that this technique works best if A's class hierarchy is stable. And for each subclass of A, it must have an apply_evaluator function defined properly.
On the other hand, this may be total overkill. For about the same amount of work, you could always just pay the price to update M::Evaluate:
class M
{
...
void Evaluate(const String& sInput, T& tResult)
{
// try to downcast to each subclass of A. Be sure to check
// sub-subclasses first
try
{
dynamic_cast<B*>(pInterface.get())->Func(sInput, tResult);
return;
}
catch (std::bad_cast& ) { }
...
// nothing worked. It must really be an A
pInterface->Func(sInput,tResult);
}
...
};
I've show in the question Templatized Virtual function how to use type erasure to get some of the effects of virtual member function. Depending on what you want to do in Func(), you can use the same technique here.