I realize that virtual template functions are not allowed in c++. Because of my specific application domain, we deal with sets of algorithms (natural for implementation through polymorphism and inheritance) and need to enforce a common interface. Particular algorithmic classes work over iterators (not surprising), however we would like to fake virtualization through these templated functions. Here is an example of a solution we came up with using boost::mpl. I realize this is lengthy, but this is a minimal code example that I could create to simulate what I am aiming for. My specific question follows after the code.
#include <iostream>
#include <vector>
#include <boost/mpl/list.hpp>
#include <boost/mpl/for_each.hpp>
using namespace std;
class A;
class B;
class C;
typedef boost::mpl::list<B, C> DerivedClassList;
template<typename Base, typename Iterator>
struct VirtualFunc{
public:
VirtualFunc(Base* _memory, Iterator _begin, Iterator _end) :
m_memory(_memory), m_begin(_begin), m_end(_end){}
template<typename T>
void operator()(T& _t) {
T* tptr = dynamic_cast<T*>(m_memory);
if(tptr != NULL){
tptr->Print(m_begin, m_end);
}
}
private:
Base* m_memory;
Iterator m_begin, m_end;
};
class A{
public:
A(){}
virtual ~A(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
boost::mpl::for_each<DerivedClassList>(VirtualFunc<A, Iterator>(this, _begin, _end));
}
};
class B : public A {
public:
B(){}
virtual ~B(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
cout << "Begin::" << *_begin << endl;
}
};
class C : public A {
public:
C(){}
virtual ~C(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
for(Iterator it = _begin; it!=_end; it++)
cout << "Iterator::" << *it << endl;
}
};
int main(){
vector<size_t> numbers;
for(size_t i = 0; i<5; i++)
numbers.push_back(i);
A* printBegin = new B();
A* printAll = new C();
//faking virtualism will print just begin
printBegin->Print(numbers.begin(), numbers.end());
//faking virtualism will print all
printAll->Print(numbers.begin(), numbers.end());
}
So what is the pitfalls of this "fake virtual" templated functions? Is there a better more concise way to do this?
Also excuse the code standards, they are what we use at my workplace.
Why not replace with classic double dispatch pattern. It seems that you know your class hierarchy at the base level - so I would use the following. It is well known, Visitor or DoubleDispatch pattern and eliminate the non efficient dynamic_cast. Frankly - if I see dynamic_cast<> I always think about double-dispatch,
Known clasees:
class A;
class B;
class C;
Start point of virtual-ism:
class IVirtualFunc {
public:
virtual void callFor(B& memory) = 0;
virtual void callFor(C& memory) = 0;
};
Implementation for the template argument:
template<typename Iterator>
class VirtualFunc : public IVirtualFunc {
public:
VirtualFunc (Iterator _begin, Iterator _end) : begin(_begin), end(_end) {}
virtual void callFor(B& memory);
virtual void callFor(C& memory);
private:
Iterator begin;
Iterator end;
};
The abstract base class for the actual implementations:
class A{
public:
template<typename Iterator>
void Print(Iterator _begin, Iterator _end) {
VirtualFunc<Iterator> vFunc(_begin, _end);
dispatch(vFunc);
}
virtual void dispatch(IVirtualFunc&) = 0;
};
First actual implementation with double dispatch for it (VirtualFunc<Iterator>::callFor(B& b)):
class B : public A {
public:
B(){}
virtual ~B(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
cout << "Begin::" << *_begin << endl;
}
virtual void dispatch(IVirtualFunc& vf) { vf.callFor(*this); }
};
template<typename Iterator>
void VirtualFunc<Iterator>::callFor(B& b)
{
b.Print(begin, end);
}
Second actual implementation with double dispatch for it (VirtualFunc<Iterator>::callFor(C& c)):
class C : public A {
public:
C(){}
virtual ~C(){}
template<typename Iterator>
void Print(Iterator _begin, Iterator _end){
for(Iterator it = _begin; it!=_end; it++)
cout << "Iterator::" << *it << endl;
}
virtual void dispatch(IVirtualFunc& vf) { vf.callFor(*this); }
};
template<typename Iterator>
void VirtualFunc<Iterator>::callFor(C& c)
{
c.Print(begin, end);
}
And the proof it works:
int main(){
vector<size_t> numbers;
for(size_t i = 0; i<5; i++)
numbers.push_back(i);
A* printBegin = new B();
A* printAll = new C();
//faking virtualism will print just begin
printBegin->Print(numbers.begin(), numbers.end());
//faking virtualism will print all
printAll->Print(numbers.begin(), numbers.end());
}
OUTPUT:
Begin::0
Iterator::0
Iterator::1
Iterator::2
Iterator::3
Iterator::4
Related
I would like to create a heterogeneous structure to store pointers to some classes so that I can loop through it and call a write() function.
The idea is this:
#include <boost/variant.hpp>
#include <vector>
template< typename T>
class A
{
public:
A(){}
~A(){}
void write();
private:
T data;
};
template< typename T>
void A<T>::write()
{
std::cout << data << std::endl;
}
int main()
{
A<int> one;
A<double> two;
typedef boost::variant<A<int>*, A<double>* > registry;
std::vector<registry> v;
v.push_back(&one);
v.push_back(&two);
for(unsigned int i =0; i< v.size(); i++)
{
v[i]->write();
}
}
However, this code does not compile. Showing the error:
error: base operand of ‘->’ has non-pointer type ‘__gnu_cxx::__alloc_traits<std::allocator<boost::variant<A<int>*, A<double>*> > >::value_type {aka boost::variant<A<int>*, A<double>*>}’
v[i]->write();
How can I fix this? I would also appreciate ideas on the implementation
v[i] returns a boost::variant<A<int>*, A<double>*> instead of a pointer to an instance of A, so you cannot use operator-> on it. You need to use boost::apply_visitor to visit the content fo the variant.
for(unsigned int i = 0; i < v.size(); i++) {
boost::apply_visitor([](auto a) { a->write(); }, v[i]);
}
Demo.
Since lambda uses auto as a parameter type is a feature of C++14, in C++11, you need to create a callable class with a template operator() as the visitor, as shown below:
struct Visitor {
using result_type = void;
template<typename T>
result_type operator()(A<T>* a) const { a->write(); }
};
for(unsigned int i = 0; i < v.size(); i++) {
boost::apply_visitor(Visitor{}, v[i]);
}
Demo.
Based on the previous answer I built:
class myVisitor
: public boost::static_visitor<>
{
public:
template< typename T>
void operator() (A<T>* a) const
{
a->write();
}
};
And use it in the code as:
for(auto x: v)
{
boost::apply_visitor(myVisitor(), x);
}
Or with a common base class as:
class tst
{
public:
virtual ~tst() {}
virtual void write() = 0;
};
template< typename T>
class A : public tst
{
public:
A(){}
~A(){}
void write();
private:
T data;
};
int main()
{
A<int> one;
A<double> two;
std::vector<tst*> v;
v.push_back(&one);
v.push_back(&two);
for(auto x: v)
{
x->write();
}
}
What do you think?
In order to work with a simplified example, let's consider some animals eating some items in a food list. The food list has a lot of different iterators for different situations.
class contains_fish
{
public:
bool operator () (const Food& food) const;
};
class is_vegetarian
{
public:
bool operator () (const Food& food) const;
};
class FoodList
{
private:
std::vector<Food> foodItems;
public:
typedef std::vector<Food>::iterator iterator;
typedef std::vector<Food>::const_iterator const_iterator;
typedef std::vector<Food>::reverse_iterator reverse_iterator;
typedef std::vector<Food>::const_reverse_iterator const_reverse_iterator;
typedef boost::filter_iterator<contains_fish,FoodList::iterator> fish_iterator;
typedef boost::filter_iterator<contains_fish,FoodList::const_iterator> fish_const_iterator;
typedef boost::filter_iterator<contains_fish,FoodList::reverse_iterator> fish_reverse_iterator;
typedef boost::filter_iterator<contains_fish,FoodList::const_reverse_iterator> fish_const_reverse_iterator;
typedef boost::filter_iterator<is_vegetarian,FoodList::iterator> vegetarian_iterator;
typedef boost::filter_iterator<is_vegetarian,FoodList::const_iterator> vegetarian_const_iterator;
typedef boost::filter_iterator<is_vegetarian,FoodList::reverse_iterator> vegetarian_reverse_iterator;
typedef boost::filter_iterator<is_vegetarian,FoodList::const_reverse_iterator> vegetarian_const_reverse_iterator;
//...
//... with corresponding begin/end functions :
FoodList::iterator begin() { return this->foodItems.begin(); }
FoodList::const_iterator begin() const { return this->foodItems.begin(); }
//...
FoodList::vegetarian_const_reverse_iterator begin_vegetarian_const_reverse() const { return boost::make_filter_iterator<is_vegetarian>(this->foodItems.rbegin(), this->foodItems.rend()); }
};
Now I want to give food (a virtual function) to each animal with iterators on the food list. Something like this code (not working due to virtual template function) :
class Animal
{
public:
virtual ~Animal() {}
template <typename FoodListIterator>
virtual void eat(FoodListIterator begin, FoodListIterator end) = 0;
};
class Dog : public Animal
{
public:
virtual ~Dog() {}
template <typename FoodListIterator>
virtual void eat(FoodListIterator begin, FoodListIterator end)
{
if(begin == end)
std::cout << "Sad day ! Nothing for me..." << std::endl;
else
{
std::cout << "I'm a dog and I'm going to eat :" << std::endl;
for(FoodListIterator it = begin; it != end; ++it)
std::cout << it->toString() << std::endl;
}
}
};
void give_fish(std::vector<Animal*>& animals, const FoodList& food_list)
{
for(unsigned long int i = 0; i < animals.size(); ++i)
animals[i]->eat(food_list.fish_begin(), food_list.fish_end());
}
I have too many different iterator to implement a virtual function for each signature.
How can I do that elegantly, without C++11 ? If it can help, I know the list of types eligible (the list of iterators described in FoodList).
You could reorganize your interface such that each Animal is fed one single Food virtually and a range of Foods non-virtually:
class Animal
{
public:
virtual ~Animal() {}
virtual void eat(Food& ) = 0; // or Food const&
template <typename Iterator>
void eat(Iterator begin, Iterator end) {
for (; begin != end; ++begin) {
eat(*begin);
}
}
};
Though if you really need the whole range, you could use something like boost::any_range:
class Animal
{
public:
using FoodRange = boost::any_range<Food, boost::forward_traversal_tag,
Food&, std::ptrdiff_t>;
virtual ~Animal() {}
virtual void eat(FoodRange ) = 0;
template <typename Iterator>
void eat(Iterator begin, Iterator end) {
eat(FoodRange{begin, end});
}
};
Background
This is purely for educational purposes. If you don't want to read the whole background, you can skip to the question at the bottom.
I have written a Queue interface (abstract class), and 2 derived implementations based on resizing arrays and linked lists.
template <typename T>
class IQueue {
public:
virtual void enqueue(T item) = 0;
virtual T dequeue() = 0;
virtual bool isEmpty() = 0;
virtual int size() = 0;
}
template <typename T>
class LinkedListQueue : public IQueue<T> {...}
template <typename T>
class ResizingArrayQueue : public IQueue<T> {...}
I wanted to be able to go over a queue's elements with an STL compliant iterator (I know queues should not be iterable), so I can use for (auto e: c) or queue.begin() / queue.end().
Because I use run-time polymorphism I had to add a client iterator class to IQueue and use the Pimpl idiom to instantiate the actual implementation specific iterators in the derived queue classes, to avoid object slicing issue.
So the augmented code looks like:
template <typename T>
class IQueue {
public:
virtual void enqueue(T item) = 0;
virtual T dequeue() = 0;
virtual bool isEmpty() = 0;
virtual int size() = 0;
public:
class IteratorImpl {
public:
virtual void increment () = 0;
virtual bool operator== (const IteratorImpl& other) const = 0;
virtual bool operator!= (const IteratorImpl& other) const = 0;
virtual T& operator* () const = 0;
virtual T& operator-> () const = 0;
virtual void swap (IteratorImpl& other) = 0;
virtual IteratorImpl* clone() = 0;
};
public:
class ClientIterator : public std::iterator<std::forward_iterator_tag, T> {
std::unique_ptr<IteratorImpl> impl;
public:
ClientIterator(const ClientIterator& other) : impl(other.impl->clone()) {}
ClientIterator(std::unique_ptr<IteratorImpl> it) : impl(std::move(it)) {}
void swap(ClientIterator& other) noexcept {
impl->swap(*(other.impl));
}
ClientIterator& operator++ () {
impl->increment();
return *this;
}
ClientIterator operator++ (int) {
ClientIterator tmp(*this);
impl->increment();
return tmp;
}
bool operator== (const ClientIterator& other) const {
return *impl == *other.impl;
}
bool operator!= (const ClientIterator& other) const {
return *impl != *other.impl;
}
T& operator* () const {
return **impl;
}
T& operator-> () const {
return **impl;
}
};
typedef ClientIterator iterator;
virtual iterator begin() = 0;
virtual iterator end() = 0;
};
and one of the derived classes implements the begin() / end() methods and the derived Iterator implementation:
template <typename T>
class LinkedListQueue : public IQueue<T> {
// ... queue implementation details.
public:
class LinkedListForwardIterator : public IQueue<T>::IteratorImpl {
// ... implementation that goes through linked list.
};
typename IQueue<T>::ClientIterator begin() {
std::unique_ptr<LinkedListForwardIterator> impl(new LinkedListForwardIterator(head));
return typename IQueue<T>::iterator(std::move(impl));
}
typename IQueue<T>::ClientIterator end() {
std::unique_ptr<LinkedListForwardIterator> impl(new LinkedListForwardIterator(nullptr));
return typename IQueue<T>::iterator(std::move(impl));
}
};
Now in order to test that the iterators work I have the following 2 functions:
template <typename T>
void testQueueImpl(std::shared_ptr<IQueue<T> > queue) {
queue->enqueue(1);
queue->enqueue(2);
queue->enqueue(3);
queue->enqueue(4);
queue->enqueue(5);
queue->enqueue(6);
std::cout << "Iterator behavior check 1st: ";
for (auto e: *queue) {
std::cout << e << " ";
}
std::cout << std::endl;
std::cout << "Iterator behavior check 2nd: ";
for (auto it = queue->begin(); it != queue->end(); it++) {
std::cout << *it << " ";
}
}
void testQueue() {
auto queue = std::make_shared<LinkedListQueue<int> >();
testQueueImpl<int>(queue);
auto queue2 = std::make_shared<ResizingArrayQueue<int> >();
testQueueImpl<int>(queue2);
}
Question
How can I get rid of the run-time polymorphism (remove IQueue, remove the iterator Pimpl implementations), and rewrite the testQueue() / testQueueImpl() functions so that:
the functions can successfully test the Stack implementations and Stack iterators, without having a base class pointer.
that both LinkedListQueue and ResizingArrayQueue adhere to some kind of a compile-time interface (the enqueue, dequeue, isEmpty, size methods are present, the begin / end methods are present, both classes contain valid iterator classes)?
Possible solution
For 1) it seems that I can simply change the template argument to be the whole container, and the program compiles successfully and runs. But this does not check for the existence of the begin() / end() / enqueue() methods.
For 2) from what I could find on the internet, it seems that the relevant solution would involve Type Traits / SFINAE / or Concepts (Container concept, forward iterator concept). It seems that Boost Concepts library allows annotating a class to conform to a container concept, but I am interested in a self-contained solution (no external libraries except STL) for educational purposes.
template <typename Container>
void testQueueImpl(Container queue) {
queue->enqueue(1);
queue->enqueue(2);
queue->enqueue(3);
queue->enqueue(4);
queue->enqueue(5);
queue->enqueue(6);
std::cout << "Size: " << queue->size() << std::endl;
std::cout << "Iterator behavior check 1st: ";
for (auto e: *queue) {
std::cout << e << " ";
}
std::cout << std::endl;
std::cout << "Iterator behavior check 2nd: ";
for (auto it = queue->begin(); it != queue->end(); it++) {
std::cout << *it << " ";
}
std::cout << std::endl;
}
void testQueue() {
auto queue = std::make_shared<LinkedListQueue<int> >();
testQueueImpl<std::shared_ptr<LinkedListQueue<int> > >(queue);
auto queue2 = std::make_shared<ResizingArrayQueue<int> >();
testQueueImpl<std::shared_ptr<ResizingArrayQueue<int> > >(queue2);
}
Here is a minimum compilable example of how you might want to do it.
Note that at the moment, this example only supports const begin() and const end().
The addition of further methods and a mutable iterator is an exercise for the reader
EDIT: provided working example of both compile time and runtime polymorphic queues that shared the same policy classes.
#include <iostream>
#include <list>
#include <vector>
#include <memory>
#include <typeinfo>
#include <typeindex>
/// COMPILE TIME Polymorphic queue of objects of type Element
template<typename Element, class Policy>
struct queue_concept
{
// Define interface
struct const_iterator;
void push_back(Element e);
const_iterator begin() const;
const_iterator end() const;
// Implementation
private:
Policy _policy;
};
// implement class methods an inner classes
template<typename Element, class Policy>
struct queue_concept<Element, Policy>::const_iterator
{
using iterator_type = typename Policy::container_type::const_iterator;
const_iterator(iterator_type iter = iterator_type {})
: _iter { std::move(iter) }
{}
const Element& operator*() const {
return *_iter;
}
const_iterator& operator++() {
std::advance(_iter, 1);
}
bool operator!=(const const_iterator& other) const {
return _iter != other._iter;
}
iterator_type _iter;
};
template<typename Element, class Policy>
void queue_concept<Element, Policy>::push_back(Element e)
{
_policy._data.push_back(std::move(e));
}
template<typename Element, class Policy>
typename queue_concept<Element, Policy>::const_iterator queue_concept<Element, Policy>::begin() const
{
return const_iterator { _policy._data.begin() };
}
template<typename Element, class Policy>
typename queue_concept<Element, Policy>::const_iterator queue_concept<Element, Policy>::end() const
{
return const_iterator { _policy._data.end() };
}
/// RUNTIME Polymorphic queue of objects of type Element
template<typename Element>
struct IQueue
{
struct const_iterator
{
struct Concept {
// virtual base class so make destructor virtual...
virtual ~Concept() = default;
virtual const Element& get_element() const = 0;
virtual void increment(std::size_t distance) = 0;
bool equal_to(const Concept& rhs)
{
if (this->get_type() == rhs.get_type()) {
return unsafe_is_equal(rhs);
}
return false;
}
virtual bool unsafe_is_equal(const Concept& rhs) const = 0;
virtual std::type_index get_type() const = 0;
// provide copy support
virtual std::unique_ptr<Concept> clone() const = 0;
};
template<class Iter>
struct Model : public Concept {
Model(Iter iter) : _iter { std::move(iter) }
{}
const Element& get_element() const override {
return *_iter;
}
void increment(std::size_t distance) override {
std::advance(_iter, distance);
}
bool unsafe_is_equal(const Concept& rhs) const override {
auto _rhs = static_cast<const Model&>(rhs);
return _iter == _rhs._iter;
}
std::type_index get_type() const override {
return std::type_index(typeid(*this));
}
std::unique_ptr<Concept> clone() const override {
return std::unique_ptr<Concept> { new Model(*this) };
}
private:
Iter _iter;
};
// constructor
template<class Iter>
const_iterator(Iter iter)
: _impl { new Model<Iter> { std::move(iter) } }
{}
// default constructor - constructs an invalid iterator
const_iterator()
{}
// provide copy support since impl is a unique_ptr
const_iterator(const const_iterator& other)
: _impl { other._impl ? other._impl->clone() : std::unique_ptr<Concept>{} }
{}
const_iterator& operator=(const_iterator& other)
{
auto p = other._impl ? other._impl->clone() : std::unique_ptr<Concept>{};
std::swap(_impl, p);
}
// since we provided copy support we must provide move support
const_iterator(const_iterator&& rhs) = default;
const_iterator& operator=(const_iterator&& rhs) = default;
const Element& operator*() const {
return _impl->get_element();
}
const_iterator& operator++() {
_impl->increment(1);
return *this;
}
bool operator!=(const const_iterator& rhs) const
{
return !(_impl->equal_to(*(rhs._impl)));
}
private:
std::unique_ptr<Concept> _impl;
};
virtual void push_back(Element e) = 0;
virtual const_iterator begin() const = 0;
virtual const_iterator end() const = 0;
};
template<class Element, class Policy>
struct QueueImpl : public IQueue<Element>
{
void push_back(Element e) override {
_policy._data.push_back(std::move(e));
}
typename IQueue<Element>::const_iterator begin() const override {
return typename IQueue<Element>::const_iterator { std::begin(_policy._data) };
}
typename IQueue<Element>::const_iterator end() const override {
return typename IQueue<Element>::const_iterator { std::end(_policy._data) };
}
Policy _policy;
};
template<class Element>
struct ResizingArrayPolicy
{
using container_type = std::vector<Element>;
container_type _data;
};
template<class Element>
struct LinkedListPolicy
{
using container_type = std::list<Element>;
container_type _data;
};
template<class Element>
std::unique_ptr<IQueue<Element>> make_poly_resizing_array_queue()
{
return std::unique_ptr<IQueue<Element>> { new QueueImpl<Element, ResizingArrayPolicy<Element>> };
}
template<class Element>
std::unique_ptr<IQueue<Element>> make_poly_linked_list_queue()
{
return std::unique_ptr<IQueue<Element>> { new QueueImpl<Element, LinkedListPolicy<Element>>{} };
}
template<class Element>
queue_concept<Element, ResizingArrayPolicy<Element>> make_static_resizing_array_queue()
{
return queue_concept<Element, ResizingArrayPolicy<Element>>{};
}
template<class Element>
queue_concept<Element, LinkedListPolicy<Element>> make_static_linked_list_queue()
{
return queue_concept<Element, LinkedListPolicy<Element>>{};
}
using namespace std;
int main()
{
// create the queues
auto pq1 = make_poly_resizing_array_queue<int>();
auto pq2 = make_poly_linked_list_queue<int>();
// put data in them
pq1->push_back(10);
pq1->push_back(20);
pq2->push_back(30);
pq2->push_back(40);
// prove that iterators are assignable and moveable
IQueue<int>::const_iterator it;
it = pq1->begin();
cout << *it << endl; // should print 10
auto i2 = pq2->begin();
it = move(i2);
cout << *it << endl; // should print 30
// prove that queues are polymorphic
auto queues = vector<unique_ptr<IQueue<int>>>{};
queues.push_back(move(pq1));
queues.push_back(move(pq2));
// print the vector of queues
for(const auto& queue_ptr : queues) {
for(const auto& item : *queue_ptr) {
cout << item << endl;
}
cout << endl;
}
// now the static versions
auto q1 = make_static_resizing_array_queue<int>();
auto q2 = make_static_linked_list_queue<int>();
q1.push_back(10);
q1.push_back(20);
q2.push_back(30);
q2.push_back(40);
cout << "static queues\n";
for(const auto& item : q1) {
cout << item << endl;
}
cout << endl;
for(const auto& item : q2) {
cout << item << endl;
}
return 0;
}
The question is not clear whether you actual need runtime polymorphism (of what, for example?)
An approach could be similiar to the one used by C++ containers: have a class that will manage the allocation/deallocation and construction/destruction of the objects.
template <typename T, class Allocator>
class Queue
{
Allocator myAllocator;
public:
void enqueue(T item)
{
myAllocator.push(item);
}
// other operations.
};
and then have something like
template <class T, template <typename ...> class Container, class ... Args>
class BasicAllocator
{
Container<T, Args...> M_list;
public:
void push(T element)
{
M_list.push_back(element);
}
auto begin() -> decltype( std::begin(M_list) )
{ return std::begin(M_list); }
auto end() -> decltype( std::end(M_list) )
{ return std::end(M_list); }
};
template<class T>
using LinkedListAllocator = BasicAllocator<T, std::list>;
template<class T>
using LinkedListQueue = Queue<T, LinkedListAllocator<T>>;
Implementing dequeue might be a little trickier.
Live example
I have written a small piece of code where I am able to call setter and getter functions packed within a functoid using mem_fun templates.
I now would like to use this approach on top of a class hierarchy where every class might have getter and setter which can be registered as pair within a vector or array to be able to call the getter and setter if needed. GUIObject and GUICompositeObject are example classes out of the described class hierarchy.
The bound_mem_fun_t for the objects have unfortunately different types and thats the reason I don't know how to integrate them into an array/vector of pointers to the functors.
In c++11 I would use std::function. Is there a way to emulate this in c++98?
Because our compiler support only c++98 I cannot use the new features of c++11 or c++14. Also boost is not allowed.
#include <functional>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
template<typename T>
struct bound_mem_fun_t
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
int operator()() { return m_GetFunc(obj); } ;
void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
bound_mem_fun_t<GUIObject> GUIObjectFunc(std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject);
GUIObjectFunc(17);
int ii = GUIObjectFunc();
bound_mem_fun_t<GUICompositeObject> GUICompObjectFunc(std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj);
GUICompObjectFunc(17);
int iChilds = GUICompObjectFunc();
return 0;
}
Here is the complete solution after #filmors answer:
#include <functional>
#include <vector>
#include <iostream>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
struct bound_mem_fun_base
{
virtual int operator()() =0;
virtual void operator()(int) =0;
};
template<typename T>
struct bound_mem_fun_t : public bound_mem_fun_base
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
virtual int operator()() { return m_GetFunc(obj); } ;
virtual void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
template<typename T> bound_mem_fun_t<T>* make_setter(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o)
{
return new bound_mem_fun_t<T> (GetFunc, SetFunc, o);
}
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
std::vector<bound_mem_fun_base*> kBoundVector;
kBoundVector.push_back(new bound_mem_fun_t<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(new bound_mem_fun_t<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
kBoundVector.push_back(make_setter<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(make_setter<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
for (int i = 0; i < 4 ; i++)
{
(*kBoundVector[i])(i*10);
int res = (*kBoundVector[i])();
std::cout << "Getter result " << res << "\n";
}
return 0;
}
Unfortunately the make_setter function does not really shorten the creation of the functor. Any ideas will be welcome.
Just give your bound_mem_fun_t<T> a common base class and use dynamic dispatch to solve your problem:
struct bound_mem_fun_base {
virtual int operator()() = 0;
virtual void operator()(int) = 0;
};
template <typename T>
struct bound_mem_fun_t : bound_mem_fun_t ...
Then you can keep pointers to bound_mem_fun_base in your vector and call the elements as (*v[0])().
Also, TR1 does contain std::tr1::function, is that available?
First a remark on std::function from c++11: That will not solve your problem, because you need an already bounded function pointer. This pointer must be bound to your object. I believe what you need is an own implementation to std::bind.
I started only a very! small Binder class which is hopefully a starting point for your needs. If you need to have template parameter lists in older c++ versions, take a look for loki. http://loki-lib.sourceforge.net/
As a hint I can give you a short example of what i did:
class A
{
private:
int val;
public:
A(int i): val(i) {}
void Do(int i) { std::cout << "A " << val<< " " << i << std::endl; }
};
class B
{
private:
int val;
public:
B(int i): val(i){}
void Go(int i) { std::cout << "B " << val << " " << i << std::endl; }
};
class Base
{
public:
virtual void operator()(int i)=0;
};
template <typename T>
class Binder: public Base
{
void (T::*fnct)(int);
T* obj;
public:
Binder( void(T::*_fnct)(int), T*_obj):fnct(_fnct),obj(_obj){}
void operator()(int i)
{
(obj->*fnct)(i);
}
};
int main()
{
A a(100);
B b(200);
// c++11 usage for this example
//std::function<void(int)> af= std::bind( &A::Do, &a, std::placeholders::_1);
//af(1);
// hand crafted solution
Base* actions[2];
actions[0]= new Binder<A>( &A::Do, &a);
actions[1]= new Binder<B>( &B::Go, &b);
actions[0]->operator()(55);
actions[1]->operator()(77);
}
So I'm trying to write a base class to handle classes that wrap std::vector, which I have working up to defining the __iter__ function. My first approach, and the one I wish to get working, is to have the begin() and end() functions in the base class. Doing this compiles fine, but when I run the code in python I get an error that looks simiar to:
Boost.Python.ArgumentError: Python argument types in
Container.__iter__(Container)
did not match C++ signature:
__iter__(boost::python::back_reference< stl_iter< std::vector< std::shared_ptr< K > > std::allocator< std::shared_ptr< K > > > >&>)
The following sample extension can be tested with
from test import *
c = Container()
for i in range(10):
c.append(K(str(i)))
for i in c:
print i
Sample extension:
#include <memory>
#include <vector>
#include <string>
#include <boost/python.hpp>
template<class T>
T* get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
template<class T>
class stl_iter {
protected:
typedef typename T::value_type V;
typedef typename T::iterator iter;
virtual T& get_vector()=0;
public:
virtual ~stl_iter() {}
virtual void append(V item) {
get_vector().push_back(item);
}
virtual iter begin() {
return get_vector().begin();
}
virtual iter end() {
return get_vector().end();
}
};
class K {
std::string val;
public:
K(std::string s) : val(s) {}
std::string get_val() const { return val; }
};
typedef std::shared_ptr<K> pK;
typedef std::vector<pK> vK;
class Container : public stl_iter<vK> {
vK items;
protected:
vK& get_vector() { return items; }
public:
// Works if I uncomment these
//vK::iterator begin() { return get_vector().begin(); }
//vK::iterator end() { return get_vector().end(); }
public:
virtual ~Container() {}
};
typedef std::shared_ptr<Container> pContainer;
typedef std::vector<pContainer> vContainer;
BOOST_PYTHON_MODULE_INIT(test) {
using namespace boost::python;
class_<K, pK>("K", init<std::string>())
.def("__str__", &K::get_val)
;
class_<Container, pContainer>("Container")
.def("append", &Container::append)
.def("__iter__", range(&Container::begin, &Container::end))
;
}
The answer was actually quite simple: make the container behave like an stl container, and then to use boost's iterator<>() function instead of range().
To do this, I had to make the typedefs in stl_iter public, and to rename them to value_type and iterator.
Heres the updated C++ code.
#include <memory>
#include <vector>
#include <string>
#include <boost/python.hpp>
template<class T>
T* get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
template<class T>
class stl_iter {
protected:
virtual T& get_vector()=0;
public:
// Next two lines changed, and made public
typedef typename T::value_type value_type;
typedef typename T::iterator iterator;
virtual ~stl_iter() {}
virtual void append(value_type item) {
get_vector().push_back(item);
}
virtual iterator begin() {
return get_vector().begin();
}
virtual iterator end() {
return get_vector().end();
}
};
class K {
std::string val;
public:
K(std::string s) : val(s) {}
std::string get_val() const { return val; }
};
typedef std::shared_ptr<K> pK;
typedef std::vector<pK> vK;
class Container : public stl_iter<vK> {
vK items;
protected:
vK& get_vector() { return items; }
public:
virtual ~Container() {}
};
typedef std::shared_ptr<Container> pContainer;
typedef std::vector<pContainer> vContainer;
BOOST_PYTHON_MODULE_INIT(test) {
using namespace boost::python;
class_<K, pK>("K", init<std::string>())
.def("__str__", &K::get_val)
;
class_<Container, pContainer>("Container")
.def("append", &Container::append)
// Use iterator() instead of range()
.def("__iter__", iterator<Container>())
;
}
range() also can be used fine, but underlying iterator anyway should support STL semantic, here is sample:
...
.def("__iter__"
, range<return_value_policy<copy_non_const_reference> >(
&my_sequence<heavy>::begin
, &my_sequence<heavy>::end))