Having a closer look at __do_visit in std::variant I grew curious about the performances of the std::variant polymorphic approach
I wrote a small test program to compare old school inheritance to the std::variant one
#include <variant>
#include <vector>
#include <iostream>
#include <string>
#include <chrono>
int i = 0;
// Polymorphism using variants
class circle
{
public:
void draw() const { i++; }
};
class line
{
public:
void draw() const { i++; }
};
using v_t = std::variant<circle, line>;
void variant_way(const std::vector<v_t>& v)
{
for (const auto &var : v)
std::visit([](const auto& o) {
o.draw();
}, var);
}
// old school
class shape
{
public:
virtual void draw() const = 0;
virtual ~shape() { }
};
class circle_in : public shape
{
public:
virtual void draw() const { i++; }
};
class line_in : public shape
{
public:
virtual void draw() const { i++; }
};
void inherit_way(const std::vector<shape*>& v)
{
for (const auto var : v)
var->draw();
}
// call and measure
template <typename F, typename D>
void run(F f, const D& data, std::string name)
{
auto start = std::chrono::high_resolution_clock::now();
f(data);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << name << ": "<< elapsed.count() << std::endl;
}
int main()
{
constexpr int howmany = 100000;
{
std::vector<v_t> v {howmany};
run(variant_way, v, "variant");
}
{
std::vector<shape*> v;
for (int i = 0; i < howmany; i++)
v.push_back(new circle_in());
run(inherit_way, v, "inherit_way");
// deallocate
}
return 0;
}
On my machine (i7, 16GB RAM), I get these results:
variant: 7487
inherit_way: 1302
I suspect that this result reflects the fact that the std::variant approach creates the vtable at each iteration while the inheriting approach does it once for all.
Is this explanation correct?
Is there a way to reduce the overhead?
Related
Assume the snippet below. How can I make this compiling/working? I do not want to move print to the String/Float class, because in my real world situation this function is combining a lot of data.
So basically I want a pointer/member to "any type (in this case string/float)" then use it, and call dynamically something else (in this case print)?
I assume that this does not work (among others) because it cannot determine at compile time which type T of ptr will have at compile time.
What is the general pattern to solve such kind of problems?
#include <iostream>
template<typename T>
class AbstractClass {
virtual T getValue()=0;
};
class StringClass : public AbstractClass<std::string> {
std::string getValue() override {
return "A";
}
};
class FloatClass : public AbstractClass<float> {
float getValue() override {
return 1;
}
};
class Processor {
public:
AbstractClass<T>* ptr;
void doIt() {
ptr=new StringClass();
print(ptr->getValue());
delete ptr;
ptr=new FloatClass();
print(ptr->getValue());
delete ptr;
}
void print(std::string i) {
std::cout << "String "<<i<<std::endl;
}
void print(float i) {
std::cout << "Float "<<i<<std::endl;
}
}
int main() {
Processor a;
a.doIt();
}
If you want an object that's 'one of' a given set of types, you can use std::variant<Ts...>. Mathematically, it represents discriminated/tagged union. This way, you don't need a pointer, neither a base class. Example:
#include <iostream>
#include <variant>
class StringClass {
std::string getValue() override {
return "A";
}
};
class FloatClass {
float getValue() override {
return 1;
}
};
using ClassWithGetValue = std::variant<StringClass, FloatClass>;
class Processor {
public:
ClassWithGetValue v;
void doIt() {
v = StringClass();
std::visit([&](auto&& v1) {
print(v1.getValue());
});
v = FloatClass();
std::visit([&](auto&& v1) {
print(v1.getValue());
});
}
void print(std::string i) {
std::cout << "String "<<i<<std::endl;
}
void print(float i) {
std::cout << "Float "<<i<<std::endl;
}
}
int main() {
Processor a;
a.doIt();
}
I am experimenting with polymorphism and boost::variant in c++11
Here is the code
#include <iostream>
#include <boost/variant.hpp>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{
width=a;
height=b;
}
};
class Rectangle: public Polygon {
public:
Rectangle() {
std::cout << "ctor rectangle" << std::endl;
}
int area()
{
return width*height;
}
};
class Triangle: public Polygon {
public:
Triangle() {
std::cout << "ctor triangle" << std::endl;
}
int area()
{
return width*height/2;
}
};
int main () {
Triangle r;
boost::variant<Rectangle, Triangle> container = r;
int x = 4;
int y = 5;
if (container.type() == typeid(Rectangle)) {
r.set_values(x,y);
std::cout << r.area() << std::endl;
} else if ( container.type() == typeid(Triangle)){
r.set_values(x,y);
std::cout << r.area() << std::endl;
}
return 0;
}
I am wondering if this is the best way to proceed. There is a repetition in the code (in main() function) where for every type (we get the type at runtime) we execute the same thing, ie set value and print the area.
Is there any better way to do this?
This is a helper class for when you want value-type variant based polymorphism.
template<class Base>
struct poly_ptr_t : boost::static_visitor<Base*> {
template<class T>
Base* operator()(T& t)const { return std::addressof(t); }
template<class...Ts>
Base* operator[](boost::variant<Ts...>& v) const {
return boost::apply_visitor( *this, v );
}
template<class...Ts>
Base const* operator[](boost::variant<Ts...> const& v) const {
return boost::apply_visitor( *this, v );
}
};
Use:
poly_ptr_t<Polygon> as_polygon;
int main() {
boost::variant<Triangle, Rectangle> u(Triangle{});
as_polygon[u]->set_values(x,y);
}
Now, area is a bit of a pain. Getting the parent Polygon won't help, because it doesn't have an area.
If we added
virtual int area() = 0;
to Polygon then
std::cout << as_polygon[v]->area();
suddenly works.
The alternative is a bit of a mess in C++11. In C++14 with appropriate boost support, we get:
std::cout << boost::apply_visitor( [](auto& e){return e.area();}, v );
or
boost::apply_visitor( [](auto& e){std::cout << e.area();}, v );
where we use a generic lambda to call area.
Or we can write an area visitor:
struct get_area : boost::static_visitor<int> {
template<class T>
int operator()(T& t)const{ return t.area(); }
};
now we can do this:
std::cout << boost::apply_visitor( get_area, v );
In none of these cases do we have the code repetition within main.
Don't use if-else constructs.
Take a look at boost. I typed a small and untested example below.
#include "boost/variant.hpp"
#include <iostream>
class my_visitor : public boost::static_visitor<void>
{
public:
void operator()(Rectangle const & i) const
{
// do something here
}
void operator()(Triangle const & i) const
{
// do something here
}
};
int main()
{
boost::variant< Triangle, Rectangle > u(Triangle());
boost::apply_visitor( my_visitor(), u );
}
Say I wish to define a member variable in a parent class and set its value in an inherited class. Perhaps these identify functionality available in the class or the nature of the child class. For example:
class A
{
public:
inline int getX() { return x; }
protected:
const int x = 0;
};
class B : public A
{
protected:
const int x = 10;
};
class C : public A
{
protected:
const int x = 50;
};
It should go without saying that scope issues will prevent the above from working properly. However, is there a way to make this work as intended?
Since the variable is meant to identify the nature of the inherited classes, I would prefer if it were const - this problem would not arise if it were not const and merely redefined in the constructor, so far as I can tell.
While fiddling with the compiler trying to make sure my example code made sense, I actually came across the fact that the way I was attempting to define the constants was C++11-specific. That led me to look into the ways it was done before, and I found this question, which shed some light on the matter indirectly.
Defining a variable in this way should be done by having the base class take an argument in its constructor, in the form of:
class A
{
public:
A( const int& type ) : x(type) {}
inline int getX() { return x; }
protected:
const int x;
};
class B : public A
{
public:
B() : A(10) {}
};
class C : public A
{
public:
C() : A(50) {}
};
This will work as intended and allow the constant x to be redefined by inherited classes.
To demonstrate the point I made in my comment, here is an example of what I think you're trying to do (deduced from comments).
I have provided both duck-typed and polymorphic solutions in the same program with a timed run through each.
I use 10 million samples of each to eliminate memory cache noise.
You will notice that the run time of the polymorphic solution is significantly less than that of the duck-typed solution.
#ifdef _WIN32
#include <Windows.h>
double get_cpu_time(){
FILETIME a,b,c,d;
if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
// Returns total user time.
// Can be tweaked to include kernel times as well.
return
(double)(d.dwLowDateTime |
((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001;
}else{
// Handle error
return 0;
}
}
#else
#include <sys/time.h>
inline double get_cpu_time() noexcept {
return (double)clock() / CLOCKS_PER_SEC;
}
#endif
#include <iostream>
#include <vector>
#include <memory>
struct A
{
A(bool copy_) : copy{copy_} {}
virtual ~A() = default;
const bool copy = false;
};
struct RealA : public A
{
RealA() : A { false } {}
};
struct CopyA : public A
{
CopyA() : A { true } {}
};
// A Thing holder will hold any object which has an interface supports do_something_to(T& thing)
struct AHolder {
template<class Thing>
AHolder(std::unique_ptr<Thing> ptr)
: _ptr { std::move(ptr) }
{
}
template<class Thing, class...Args>
static AHolder construct(Args&&...args)
{
return AHolder { std::make_unique<model<Thing>>(std::forward<Args>(args)...) };
}
void do_something() const {
_ptr->do_something();
}
private:
struct concept {
virtual ~concept() = default;
virtual void do_something() = 0;
};
template<class Thing> struct model : concept {
template<class...Args>
model(Args&&...args) : _thing { std::forward<Args>(args)... } {}
private:
void do_something() override {
do_something_to(_thing);
}
Thing _thing;
};
std::unique_ptr<concept> _ptr;
};
using namespace std;
size_t copies_processed = 0;
size_t reals_processed = 0;
void do_something_to(const CopyA&)
{
// simulate work
++copies_processed;
}
void do_something_to(const RealA&)
{
// simulate work
++reals_processed;
}
int main(int argc, char **argv) {
std::vector<std::unique_ptr<A>> duck_typing;
std::vector<AHolder> polymorphic;
constexpr size_t samples = 10000000;
for (size_t i = 0 ; i < samples ; ++i) {
if (i % 2) {
duck_typing.push_back(make_unique<RealA>());
polymorphic.emplace_back(AHolder::construct<RealA>());
}
else {
duck_typing.push_back(make_unique<CopyA>());
polymorphic.emplace_back(AHolder::construct<CopyA>());
}
}
auto duck_start = get_cpu_time();
// nasty duck-typing solution
for (const auto& ptr : duck_typing) {
if (ptr->copy) {
do_something_to(*(static_cast<CopyA*>(ptr.get())));
}
else {
do_something_to(*(static_cast<RealA*>(ptr.get())));
}
}
auto duck_stop = get_cpu_time();
auto poly_start = get_cpu_time();
for (const auto& a_like : polymorphic) {
a_like.do_something();
}
auto poly_stop = get_cpu_time();
cout << "duck typing : " << duck_stop - duck_start << endl;
cout << "polymorphic : " << poly_stop - poly_start << endl;
cout << "copies processed : " << copies_processed << endl;
cout << "reals processed : " << reals_processed << endl;
return 0;
}
sample output :
duck typing : 0.162985
polymorphic : 0.137561
copies processed : 10000000
reals processed : 10000000
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);
}
Sorry for the long example, but the question is simple. I'm using basic Visitor Pattern, with a mediator to manage several concrete Visitor_pick : public DataVisitor objects. The conrete mediator, SimulatorMediator, fills a list with Visitor_pick objects, then wants to call std::thread on a DataVisitor member function. I have tried several variants, using mem_fun1_t<>, etc., with no luck. Can't compile. What is the correct syntax?
The call in question should be at line 205 - I'd like to attach threads to v->visit_SpreadData, a unary function, then populate threadVec. Any help would be appreciated.
#include <iostream>
#include <ostream>
#include <iterator>
#include <list>
#include <vector>
#include <algorithm>
#include <thread>
class PublishEvent;
class Subscriber
{
public:
virtual void update(const PublishEvent *e) = 0;
~Subscriber() = default;
};
class Publisher
{
public:
void attach(Subscriber*);
void detach(Subscriber*);
void notify(const PublishEvent*);
protected:
std::list<Subscriber*> subscribers_;
};
inline void Publisher::
notify(const PublishEvent *e)
{
for (auto &s : subscribers_)
s->update(e);
}
inline void Publisher::
attach(Subscriber *s)
{
subscribers_.push_back(s);
}
inline void Publisher::
detach(Subscriber *s)
{
// inefficient for large nubmer of susbscribers
subscribers_.remove(s);
}
class Mediator;
class SpreadData;
class DataElement;
class DataVisitor : public Publisher, public Subscriber
{
public:
virtual ~DataVisitor() {}
// visit method
virtual void visit_SpreadData(SpreadData *SD) = 0;
// from Publisher::
void update(const PublishEvent *e) override;
void setMediator(Mediator *m)
{
m_ = m;
}
float get_payload() const
{
return payload_;
}
void set_payload(float p)
{
payload_ = p;
}
virtual void gendata(DataElement*) = 0;
protected:
DataVisitor() {}
private:
Mediator *m_;
float payload_;
};
class DataElement
{
public:
virtual ~DataElement() {};
void Accept(DataVisitor&);
protected:
DataElement() {};
};
void DataElement::Accept(DataVisitor &d)
{
d.gendata(this);
}
class SpreadData : public DataElement
{
public:
typedef std::vector<float> return_data_type;
SpreadData() { initiate(); };
SpreadData(std::string filename) { initiate();};
void printdata() const
{
std::copy(data_.begin(),
data_.end(),
std::ostream_iterator<float>(std::cout, " : "));
std::cout << std::endl;
}
return_data_type getdata() const
{
return data_;
}
private:
void initiate()
{
for(int i=0;i<100;i++)
data_.push_back(static_cast<float>(i));
}
return_data_type data_;
};
void DataVisitor::update(const PublishEvent *e)
{
// implementation details
};
template<int N>
class Visitor_pick : public DataVisitor
{
public:
Visitor_pick()
{set_payload(0.); }
// from DataVisitor
void visit_SpreadData(SpreadData*) override;
// from DataVisitor
void gendata(DataElement*);
};
template<int N>
void Visitor_pick<N>::visit_SpreadData(SpreadData *SD)
{
SD->Accept(*this);
}
template<int N>
void Visitor_pick<N>::gendata(DataElement *d)
{
// implementation details
SpreadData *SD = dynamic_cast<SpreadData*>(d);
SpreadData::return_data_type r = SD->getdata();
set_payload(r[N]);
}
class Mediator
{
public:
virtual ~Mediator() = default;
virtual void mediate(DataElement*) = 0;
protected:
Mediator() = default;
virtual void CreateVisitors() = 0;
std::list<DataVisitor*> visitors_;
};
class Mediator_1 : public Mediator
{
public:
Mediator_1()
{
CreateVisitors();
}
void mediate(DataElement*);
private:
void CreateVisitors();
};
void Mediator_1::CreateVisitors()
{
visitors_.push_back(new Visitor_pick<37>());
visitors_.push_back(new Visitor_pick<42>());
visitors_.push_back(new Visitor_pick<47>());
visitors_.push_back(new Visitor_pick<52>());
visitors_.push_back(new Visitor_pick<57>());
}
void Mediator_1::mediate(DataElement *SD)
{
typedef std::mem_fun1_t<void,DataVisitor,SpreadData*> Visitor_fn;
std::cout << "Mediating hard..." << std::endl;
std::vector<std::thread> threadVec;
for(auto &v : visitors_)
{
// Use Visitor_fn to spawn thread on
// unary function v->visit_SpreadData,
// place at back of threadVec
}
for_each(threadVec.begin(), threadVec.end(),
std::mem_fn(&std::thread::join));
for(auto &v : visitors_)
std::cout << "Payload: " << v->get_payload() << std::endl;
}
int main(int argc, char **argv)
{
SpreadData *SD = new SpreadData();
Mediator_1 *M = new Mediator_1();
M->mediate(SD);
delete SD;
delete M;
return 0;
}