Variant for mpl types sequences as a class member - how? - variant

Please advice, how I can solve the following problem – I want to have class member variable boost::variant type which has a type from defined mpl type sequence. After, in main, I want to call a method which calls method for every class method defined in sequence .. :) A little bit complicated but let me show:
struct worker1
{
void init()
{
std::cout << "Worker1 init called" << std::endl;
}
};
struct worker2
{
void init()
{
std::cout << "Worker2 init called" << std::endl;
}
};
typedef mpl::vector< worker1, worker2> workers;
template< typename U> struct process3
{
process3()
{
factory();
}
struct factoryrun
{
template< typename T > void operator()(T& x)
{
std::cout << "Factory entry" << std::endl;
std::cout << "Type is = " << typeid( T ).name() << std::endl;
m_t3.push_back( x ); // FAIL!!! :(( Doesn't work
}
};
struct runinit
{
template<typename T> void operator()(T& x)
{
x.init();
}
};
void init()
{
mpl::for_each<U>( runinit() );
}
void factory()
{
std::cout << "Factory start" << std::endl;
mpl::for_each<U>( factoryrun() );
}
typedef typename boost::make_variant_over< U >::type types; // FAIL!!! Doesn't work because I need to have variant<worker1, worker2> but not variant<workers>
static std::vector< boost::variant<types> > m_t;
};
template<typename K> std::vector< boost::variant<K> > process<K>::m_t;
int main() {
process<workers> prs;
// Here should be called init() for worker1 and worker2
prs.init();
return 0;
}

The problem is solved. Such a code is working
typedef mpl::vector< worker1, worker2> workers;
template< typename U> struct process3
{
process3()
{
factory();
}
struct factoryrun
{
template< typename T > void operator()(T& x)
{
std::cout << "Factory entry" << std::endl;
std::cout << "Type is = " << typeid( T ).name() << std::endl;
m_t3.push_back( x );
}
};
struct runinit
{
template<typename T> void operator()(T& x)
{
x.init();
}
};
void init()
{
mpl::for_each<U>( runinit() );
}
void factory()
{
std::cout << "Factory start" << std::endl;
mpl::for_each<U>( factoryrun() );
}
typedef typename boost::make_variant_over< U >::type types;
typedef std::vector< boost::variant<types> > Vector; // Make typedef to simplify
static Vector m_t3;
};
template<typename U> typename process3<U>::Vector process3<U>::m_t3;
int main() {
process3<workers> prs3;
prs3.init();
return 0;
}
Output:
Factory start
Factory entry
Type is = 7worker1
Factory entry
Type is = 7worker2
Worker1 init called
Worker2 init called

I am really sorry but first version of this code is incorrect. For each call of init, run and stop new objects worker1 and worker2 are created (each time constructor os worker1 and worker2 called). So m_t3 variable is useless.
Bellow is correct code. As you may see constructors of worker1 and worker2 are called one time.
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
struct worker1
{
worker1()
{
std::cout << "Worker1 ctor" << std::endl;
}
void init()
{
std::cout << "Worker1 init called. Object address [" << this << "]" << std::endl;
}
void run()
{
std::cout << "Worker1 run called. Object address [" << this << "]" << std::endl;
}
void stop()
{
std::cout << "Worker1 stop called. Object address [" << this << "]" << std::endl;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
struct worker2
{
worker2()
{
std::cout << "Worker2 ctor" << std::endl;
}
void init()
{
std::cout << "Worker2 init called. Object address [" << this << "]" << std::endl;
}
void run()
{
std::cout << "Worker2 run called. Object address [" << this << "]" << std::endl;
}
void stop()
{
std::cout << "Worker2 stop called. Object address [" << this << "]" << std::endl;
}
};
typedef mpl::vector< worker1, worker2 > workers;
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
template< typename U> struct process3
{
process3()
{
factory();
}
struct factoryrun
{
template< typename T > void operator()(T& x)
{
std::cout << "Factory entry" << std::endl;
std::cout << "Type is = " << typeid( T ).name() << std::endl;
m_t3.push_back( x );
}
};
void init()
{
static init_visitor vis;
std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
}
void run()
{
static run_visitor vis;
std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
}
void stop()
{
static stop_visitor vis;
std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
}
typedef typename boost::make_variant_over< U >::type types;
typedef std::vector<types> Vector; // Make typedef to simplify
static Vector m_t3;
struct init_visitor: public boost::static_visitor<>
{
template <typename T>
void operator()( T& x )
{
std::cout << "Init visitor type=" << typeid(x).name() << std::endl;
x.init();
}
};
struct run_visitor: public boost::static_visitor<>
{
template <typename T>
void operator()( T& x )
{
std::cout << "Run visitor type=" << typeid(x).name() << std::endl;
x.run();
}
};
struct stop_visitor: public boost::static_visitor<>
{
template <typename T>
void operator()( T& x )
{
std::cout << "Stop visitor type=" << typeid(x).name() << std::endl;
x.stop();
}
};
};
template<typename K> typename process3<K>::Vector process3<K>::m_t3;
int main() {
process3<workers> prs3;
prs3.init();
prs3.run();
prs3.stop();
return 0;
}
Output:
Factory start
Worker1 ctor
Factory entry
Type is = 7worker1
Worker2 ctor
Factory entry
Type is = 7worker2
Init visitor type=7worker1
Worker1 init called. Object address [0x21bf038]
Init visitor type=7worker2
Worker2 init called. Object address [0x21bf048]
Run visitor type=7worker1
Worker1 run called. Object address [0x21bf038]
Run visitor type=7worker2
Worker2 run called. Object address [0x21bf048]
Stop visitor type=7worker1
Worker1 stop called. Object address [0x21bf038]
Stop visitor type=7worker2
Worker2 stop called. Object address [0x21bf048]

Related

Is it possible to add `<<` and `>>` operators to a structure itself for serialization to CArchive? [duplicate]

I just want to print the two values of my structure, but can't compile my code - I get: no operator “<<” matches these operands.
#include <iostream>
using namespace std;
struct SCoor
{
int i, j;
bool operator == (const SCoor & tmp) const
{
return (i == tmp.i && j == tmp.j);
}
bool operator < (const SCoor & tmp) const
{
return (i < tmp.i || (i == tmp.i && j < tmp.j));
}
ostream& operator << (ostream &o) {
return o << i << " " << j;
}
};
int main()
{
SCoor tmp = { 3, 3 };
cout << tmp;
return 0;
}
How do I have to overload the operator "<<"?
You overload the << operator as a member function if you want your structure to be on the left hand side of the expression. So:
struct SCoor
{
// ...
SCoor& operator << (Stuff const& s) {
// ...
return *this;
}
};
// ...
Stuff stuff;
SCoor scoor;
scoor << s; // insert s into my SCoor
If you want to make your struct the right hand side of the << expression you have to define a standalone function:
std::ostream& operator<<(std::ostream& os, SCoor const& scoor)
{
return os << scoor.i << " " << scoor.j;
}
However it is quite common to make the external function a friend function and to define it in the struct definition:
struct SCoor
{
// ...
friend std::ostream& operator<<(std::ostream& os, SCoor const& scoor)
{
return os << scoor.i << " " << scoor.j;
}
};
// ...
SCoor scoor;
std::cout << scoor << '\n';
But it is not a member of your struct, it is just defined inside its definition for convenience.

How to enumerate all member variables of a class / struct in c++

I'm working on some kind of simple reflection for c++ structs where i want to recursivly iterate over all member variables.
The code below almost does what i want but my compiler complians: "recursive type or function dependency context too complex" coming form aggregate_arity<MemberType>::size() which is based on Orients aggregate_arity implementation.
Example usage case:
struct B
{
SPVStruct;
var_t<float2_t, true> f4;
};
struct A
{
SPVStruct;
var_t<float2_t, true> f2;
var_t<float3_t, true> f3;
float d;
B b;
};
A a{};
InitializeStruct<A, true>(a);
Implementation:
struct TSPVStructTag {};
#ifndef SPVStruct
#define SPVStruct typedef TSPVStructTag SPVStructTag;
#endif
template< class, class = std::void_t<> >
struct has_spv_tag : std::false_type { };
template< class T >
struct has_spv_tag<T, std::void_t<typename T::SPVStructTag>> : std::true_type { };
template <class T>
void InitVar(T& _Member) {}
template <class T, bool Assemble>
void InitVar(var_t<T, Assemble>& _Member)
{
// actual stuff happening here
}
template <size_t N, class T, bool Assemble>
void InitStruct(T& _Struct)
{
if constexpr(N > 0u)
{
auto& member = get<N-1>(_Struct);
using MemberType = typename std::decay_t<decltype(member)>;
if constexpr(has_spv_tag<MemberType>::value)
{
constexpr size_t n = aggregate_arity<MemberType>::size(); // this is the complex recursion that blows up
InitStruct<n, MemberType, Assemble>(member);
}
else
{
InitVar(member);
InitStruct<N - 1, T, Assemble>(_Struct);
}
}
}
template <class T, bool Assemble>
void InitializeStruct(T& _Struct)
{
constexpr size_t N = aggregate_arity<T>::size();
InitStruct<N, T, Assemble>(_Struct);
}
Example
I use the has_spv_tag to mark structs that should be reflected. I can't wait for c++20 with actual reflection support :(
Thanks for your help!
Edit:
I got it to compile and changed the iteration order. Now a different problem comes up: constexpr size_t M = aggregate_arity::size() returns 0 even for the same type it returned the correct value earlier. i verified that the type is infact the same (first struct type B) by comparing the hash from typeid. How is it possible to that aggregate returns two different values for the exact same type?
template <class T, bool Assemble>
constexpr bool is_var_t(var_t<T, Assemble>& _Member) { return true; }
template <class T>
constexpr bool is_var_t(T& _Member) { return false; }
template <class T>
void InitVar(T& _Member) { std::cout << typeid(T).name() << std::endl; }
template <class T, bool Assemble>
void InitVar(var_t<T, Assemble>& _Member)
{
// actual stuff happening here
std::cout << typeid(T).name() << std::endl;
}
template <size_t n, size_t N, class T>
void InitStruct(T& _Struct)
{
std::cout << "n " << n << " N " << N << std::endl;
if constexpr(n < N)
{
decltype(auto) member = get<n>(_Struct);
using MemberType = std::remove_cv_t<decltype(member)>;
std::cout << typeid(MemberType).hash_code() << std::endl;
if (is_var_t(member))
{
InitVar(member);
InitStruct<n + 1, N, T>(_Struct);
}
else
{
constexpr size_t M = aggregate_arity<MemberType>::size();
InitStruct<0, M, MemberType>(member);
}
}
}
Edit 2: example for the new version: http://coliru.stacked-crooked.com/a/b25a84454d53d8de
Antony Polukhin pointed out the problem: MemberType still had the reference from get(_Struct). The code works with
MemberType = std::remove_reference_t<std::remove_cv_t<decltype(member)>>;
template <size_t n, size_t N, class T>
void InitStruct(T& _Struct)
{
if constexpr(n < N)
{
decltype(auto) member = get<n>(_Struct);
using MemberType = std::remove_reference_t<std::remove_cv_t<decltype(member)>>;
if constexpr(has_spv_tag<MemberType>::value)
{
InitStruct<0, aggregate_arity<MemberType>::size(), MemberType>(member);
}
else
{
InitVar(member);
}
InitStruct<n + 1, N, T>(_Struct);
}
}
I now use has_spv_tag<MemberType>::value to identify which member is a struct that i want to enumerate. There was also a bug with the order of InitStruct<n + 1, N, T>(_Struct);

templated class that contains another templated class

I am writing templated classes, specifically a templated class that stores another templated class in an array. I am having trouble with getting the pair members thing1 and thing2 set. They are getting printed out as garbage variables.
#ifndef ARRAY_H
#define ARRAY_H
#include"Pair.h"
#include<iostream>
using namespace std;
template<typename T>
class Array
{
template<typename U>
friend ostream & operator<<(ostream & out, const Array<U> &a);
private:
int size;
T* tPtr;
public:
Array(int s);
Array();
~Array();
T& operator[](int sub);
T operator[](int sub)const;
const Array<T> &operator =(const Array<T> &);
int getLength(){return size;};
};
template<typename T>
Array<T>::Array():size(0),tPtr(NULL)
{
}
template<typename T>
Array<T>::Array(int s):size(s)
{
tPtr = new T [size];
}
template<typename T>
Array<T>::~Array()
{
delete [] tPtr;
}
template<typename T>
T& Array<T>::operator[](int sub)
{
if(sub<0 || sub>size)
throw out_of_range("subscript out of range");
return tPtr[sub];
}
template<typename T>
T Array<T>::operator[](int sub)const
{
if(sub<0 || sub>size)
throw out_of_range("subscript out of range");
return tPtr[sub];
}
template<typename T>
const Array<T> &Array<T>::operator =(const Array<T> &right)
{
if(&right !=this)
{
if(size!=right.size)
{
delete [] tPtr;
size=right.size;
tPtr= new T[size];
}
for(int i =0;i<size;i++)
tPtr[i] = right.tPtr[i];
}
return *this;
}
template<typename U>
ostream & operator<<(ostream &out, const Array<U> &a)
{
for(int i =0;i<a.size;i++)
{
out<<a.tPtr[i];
}
out<<endl;
return out;
}
#endif
#ifndef PAIR_H
#define PAIR_H
#include <iostream>
using namespace std;
template<typename T,typename U>
class Pair {
private:
T thing1;
U thing2;
public:
Pair(){};
Pair( T thing1, U thing2) : thing1(thing1), thing2(thing2) {}
ostream & display(ostream & out=cout) const;
};
template<typename T,typename U>
ostream & Pair<T, U>::display(ostream & out) const {
return (out << "(" << thing1 << ", " << thing2 << ")");
}
template<typename T,typename U>
ostream & operator<<(ostream & out, const Pair<T,U> & pair) {
return pair.display(out);
}
#endif
#include "Pair.h"
#include "Array.h"
#include<string>
#include<iostream>
using namespace std;
template<typename T, typename U>
Array< Pair<T, U> >zip(Array<T> & lhs,Array<U> & rhs)
{
int zipLen = (lhs.getLength() < rhs.getLength() ? lhs.getLength() : rhs.getLength());
Array< Pair<T, U> >zipped(zipLen);
for (int i=0; i<zipLen; i++)
zipped[i] = Pair<T, U>(lhs[i], rhs[i]);
return zipped;//return array object
}
int main()
{
Array<int> a1(5);
Array<char>a2(3);
Array<Pair<int,char>>a3;
for(int i =1;i<5;i++)
a1[i-1]=i;
for(char ch='a';ch<='c';ch++)
a2[ch-'a']=ch;
a3=zip(a1,a2);//this is the line where I seem to lose all my data
cout<<a3;
system("pause");
return 0;
}
zipped is a local object. When the scope is over, its destructor will be called. Also the destructor of the two Array class objects inside zipped object will also get called. In the Array class the destructor, you are deleting the dynamic allocation. That's why you are see the garbage values. :)

Visual C++ won't let me use template?

Here's a quick template Dequeue object I made and it worked fine on mac terminal but visual c++ won't work for me. Sorry ahead of time if this is a dumb question, I'm a bit new to C++ and templates. Here's the code:
#include <iostream>
using namespace std;
template <typename T>
class Dequeue;
template <typename T>
class node;
template <typename T>
ostream& operator<<(ostream&, const Dequeue<T>&);
template <typename T>
class node{
public:
node<T>* next;
node<T>* prev;
T data;
node(T data=T(), node<T>* next=NULL, node<T>* prev=NULL);
};
template <typename T>
node<T>::node(T _data, node<T>* _next, node<T>* _prev){
data = _data;
next = _next;
prev = _prev;
}
template <typename T>
class Dequeue{
private:
node<T>* head;
node<T>* tail;
int _size;
void clear();
public:
Dequeue();
~Dequeue();
Dequeue(const Dequeue<T>&);
const Dequeue<T>& operator=(const Dequeue<T>&);
friend ostream& operator<< <>(ostream&, Dequeue<T>&);
void push_front(T&);
void push_back(T&);
void pop_front();
void pop_back();
T front();
T back();
int size();
bool isEmpty();
};
template <typename T>
Dequeue<T>::Dequeue(){
_size = 0;
head = NULL;
tail = NULL;
}
template <typename T>
Dequeue<T>::~Dequeue(){
clear();
}
template <typename T>
void Dequeue<T>::clear(){
while(_size > 0)
pop_front();
}
template <typename T>
Dequeue<T>::Dequeue(const Dequeue<T>& other){
head = NULL;
tail = NULL;
_size = 0;
*this = other;
}
template <typename T>
const Dequeue<T>& Dequeue<T>::operator=(const Dequeue<T>& other){
if(this = &other)
return *this;
clear();
node<T>* np = other.head;
while(np!=NULL){
node<T>* p = new node<T>(np->data);
if(head == tail == NULL)
head = tail = p;
else{
tail->next = p;
p->prev = tail;
}
tail = p;
np = np->next;
}
_size = other._size;
return *this;
}
template <typename T>
ostream& operator<<(ostream& out_str, Dequeue<T>& other){
node<T>* np = other.head;
while(np != NULL){
out_str << np->data << endl;
np = np->next;
}
return out_str;
}
template <typename T>
void Dequeue<T>::push_front(T& object){
node<T>* np = new node<T>(object);
np->next = head;
head->prev = np;
head = np;
_size++;
}
template <typename T>
void Dequeue<T>::push_back(T& object){
node<T>* np = new node<T>(object);
tail->next = np;
np->prev = tail;
tail = np;
_size++;
}
template <typename T>
void Dequeue<T>::pop_front(){
node<T>* np = head;
head = head->next;
delete np;
head->prev=NULL;
_size--;
}
template <typename T>
void Dequeue<T>::pop_back(){
node<T>* np = tail;
tail = np->prev;
delete np;
tail->next = NULL;
size--;
}
template <typename T>
T Dequeue<T>::front(){
return head->data;
}
template <typename T>
T Dequeue<T>::back(){
return tail->data;
}
template <typename T>
int Dequeue<T>::size(){
return _size;
}
template <typename T>
bool Dequeue<T>::isEmpty(){
if(size == 0)
return true;
else
return false;
}
int main(){
Dequeue<int> A;
A.push_back(5);
A.push_front(6);
A.push_back(7);
cout << A << endl;
cin.get();
return 0;
}
And here are the errors I'm getting:
1>------ Build started: Project: Kevin, Configuration: Debug Win32 ------
1> Dequeue.cpp
1>c:\users\kevin nguyen\documents\visual studio 2010\projects\kevin\kevin\dequeue.cpp(184): error C2664: 'Dequeue<T>::push_back' : cannot convert parameter 1 from 'int' to 'int &'
1> with
1> [
1> T=int
1> ]
1>c:\users\kevin nguyen\documents\visual studio 2010\projects\kevin\kevin\dequeue.cpp(185): error C2664: 'Dequeue<T>::push_front' : cannot convert parameter 1 from 'int' to 'int &'
1> with
1> [
1> T=int
1> ]
1>c:\users\kevin nguyen\documents\visual studio 2010\projects\kevin\kevin\dequeue.cpp(186): error C2664: 'Dequeue<T>::push_back' : cannot convert parameter 1 from 'int' to 'int &'
1> with
1> [
1> T=int
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Your issue is that in your declarations, you're trying to take a reference to T. In this case, the literals you are passing in to your function ( A.push_back(5), for example) is not necessarily something that can be taken a reference of. Your declaration should probably look more like this:
/* use `const` */
void Dequeue<T>::push_front( const T& object )
/* Same for push_back: use `const` */
void Dequeue<T>::push_back( const T& object )
Const will allow you to pass constant data as a reference. You make a copy of it anyways, so make sure all your declarations all the way down use const if they are taking a reference.
Also, it may be wise not to tell your T data parameter in your node to default to a freshly created T. That will force any data type you use with your Linked List to have a default constructor. Just take a const T& data instead, or no T at all.

How to compile this VC++ program?

Im very new to VC++. Yesterday my VC++ instructor gave us this code and asked us to make it as a exe. I have no idea of where to start and end. How to make this single file into exe. How and where to paste this working code in visual studio. If my question sounds too dumb, sorry. But i'm. Please help me out in making an exe from this single file. By the way this is Josephus circle algorithm
Code :
//////////////////Header file
#include<iostream.h>
template <class T>
class ex
{
private:
struct node
{
T data;
struct node *next;
};
struct node *head,*front,*rear;
public:
ex()
{
head=new node;
head->next=NULL;
front=rear=head;
}
void enqueue(T x);
T dequeue();
void print();
void move_next();
};
//////////////////Implementation file
#include "ex.h"
template <class T>
void ex<T>::enqueue(T x)
{
node *p;
p=new node;
p->data=x;
if(head->next==NULL)
{
front=rear=p;
head->next=p;
p->next=p;
}
else
{
rear->next=p;
p->next=front;
rear=rear->next;
}
}
template<class T>
T ex<T>::dequeue()
{
node *t;
T x;
t=front;
x=t->data;
front=front->next;
rear->next=front;
delete(t);
return x;
}
template<class T>
void ex<T>::print()
{
node *p=front;
do
{
cout<<p->data<<endl;
p=p->next;
}while(p!=rear->next);
}
template<class T>
void ex<T>::move_next()
{
front=front->next;
rear=rear->next;
}
/////////////////Application file
#include "ex.cpp"
void main()
{
ex<int> e;
int m,n,i,d;
cout<<"Enter the number of people";
cin>>n;
cout<<"Enter the number of passes";
cin>>m;
for(i=1;i<=n;i++)
e.enqueue(i);
cout<<"The players are
";
e.print();
cout<<"Eliminated in order
";
while(n>1)
{
for(i=1;i<=m;i++)
e.move_next();
d=e.dequeue();
cout<<d<<endl;
n--;
}
d=e.dequeue();
cout<<"Winning player: "<<d<<endl;
}
Make the first file named ex.h
#include<iostream.h>
template <class T>
class ex
{
private:
struct node
{
T data;
struct node *next;
};
struct node *head,*front,*rear;
public:
ex()
{
head=new node;
head->next=NULL;
front=rear=head;
}
void enqueue(T x);
T dequeue();
void print();
void move_next();
};
Second file into ex.cpp
#include "ex.h"
template <class T>
void ex<T>::enqueue(T x)
{
node *p;
p=new node;
p->data=x;
if(head->next==NULL)
{
front=rear=p;
head->next=p;
p->next=p;
}
else
{
rear->next=p;
p->next=front;
rear=rear->next;
}
}
template<class T>
T ex<T>::dequeue()
{
node *t;
T x;
t=front;
x=t->data;
front=front->next;
rear->next=front;
delete(t);
return x;
}
template<class T>
void ex<T>::print()
{
node *p=front;
do
{
cout<<p->data<<endl;
p=p->next;
}while(p!=rear->next);
}
template<class T>
void ex<T>::move_next()
{
front=front->next;
rear=rear->next;
}
And the third file into Main.cpp or something.
#include "ex.cpp"
void main()
{
ex<int> e;
int m,n,i,d;
cout<<"Enter the number of people";
cin>>n;
cout<<"Enter the number of passes";
cin>>m;
for(i=1;i<=n;i++)
e.enqueue(i);
cout<<"The players are
";
e.print();
cout<<"Eliminated in order
";
while(n>1)
{
for(i=1;i<=m;i++)
e.move_next();
d=e.dequeue();
cout<<d<<endl;
n--;
}
d=e.dequeue();
cout<<"Winning player: "<<d<<endl;
}
Then compile it. Also, it's supposed to be int main() not void main()
To add to Alex F. answer, you will also need to create an ex.h file and an ex.cpp file and paste their respective code inside

Resources