Pipeline class storing different templates with constraints - c++

I have a class template DataProcessor, which looks like this:
struct DataProcessorBase
{
typedef std::shared_ptr<DataProcessorBase> Ptr;
}; // struct DataProcessorBase
template <class _Input, class _Output>
struct DataProcessor : DataProcessorBase
{
typedef _Input Input;
typedef _Output Output;
virtual Output process(const Input * input) = 0;
}; // struct DataProcessor
I am looking to create a Pipeline class, which concatenates multiple DataProcessor instances together. This means that the Output of processor 1 must match the input of processor 2, and so forth. Something like the following:
template <class _Input, class _Output>
class Pipeline : DataProcessor<_Input, _Output>
{
public:
Output process(const Input * input);
private:
std::vector<DataProcessorBase::Ptr> _processors;
}; // class Pipeline
template <class _Input, class _Output>
_Output Pipeline<_Input, _Output>::process(const _Input * input)
{
// this is where I start guessing...
auto rawPtr = dynamic_cast<DataProcessor<_Input, TYPEOFFIRSTPROCESSORSOUTPUT>*>(_processors[0]);
assert(rawPtr);
for (size_t i = 0; i < _processors.size(); ++i)
{
...
}
}
I can tell that this way of implementing Pipeline::process is not the right way. Can someone point me in the right direction?

Decouple the in and out calls.
Data coming in and data coming out should happen at different steps. Then each consumer of data can know what it needs to demand, and do the casting for you (possibly throwing or error flagging if things go wrong).
struct processor {
virtual ~processor () {};
virtual bool can_read_from( processor const& ) const = 0;
virtual void read_from( processor& ) = 0;
virtual bool ready_to_sink() const = 0;
virtual bool ready_to_source() const = 0;
};
template<class T>
struct sink {
virtual void operator()( T&& t ) = 0;
virtual ~sink() {}
};
template<class T>
struct source {
virtual T operator()() = 0;
virtual ~source() {}
};
template<class In, class Out, class F>
struct step: processor, sink<In>, source<Out> {
F f;
step( F&& fin ):f(std::move(fin)) {}
step(step&&)=default;
step(step const&)=default;
step& operator=(step&&)=default;
step& operator=(step const&)=default;
step()=default;
std::experimental::optional<Out> data;
virtual void operator()( In&& t ) final override {
data = f(std::move(t));
}
virtual bool ready_to_sink() const {
return !data;
}
virtual Out operator()() final override {
auto tmp = std::move(data);
data = {};
return std::move(*tmp);
}
virtual bool ready_to_source() const final override {
return static_cast<bool>(data);
}
virtual bool can_read_from( processor const& o ) final override {
return dynamic_cast<source<In> const*>(&o);
}
virtual void read_from( processor &o ) final override {
(*this)( dynamic_cast<source<In>&>(o)() );
}
};
template<class In, class Out>
struct pipe {
std::shared_ptr<processor> first_step;
std::vector< std::shared_ptr<processor> > steps;
pipe(std::shared_ptr<processor> first, std::vector<std::shared_ptr<processor>> rest):
first_step(first), steps(std::move(rest))
{}
Out operator()( In&& in ) {
(*dynamic_cast<sink<In>*>(steps.first_step.get()))( std::move(in) );
auto last = first_step;
for (auto step:steps) {
step->read_from( *last );
last = step;
}
return (*dynamic_cast<source<Out>*>(last.get())();
}
};
template<class In, class Out>
struct pipeline:step<In, Out, pipe<In,Out>> {
pipeline( std::shared_pointer<processor> first, std::vector<std::shared_ptr<processor>> steps ):
step<In, Out, pipe<In,Out>>({ first, std::move(steps) })
{}
};

Related

program termination only in release mode when using __int128 and templates

I wrote some kind of index and I am trying to use it.
When I run the program in debug mode everything seems to be fine, but in release mode the program exits with code -1073741819 (hex: ‭FFFFFFFFC0000005‬); this seems to be an access violation.
The code uses data type unsigned __int128. When I replace this by uint64_t the program works also in release mode.
I am not sure, but using templates could also play a role. And even commenting out a function call (FindAllByFirstID in SomeFunc) that is never reached leads to seemingly correct execution in release mode.
I am not experienced in C++. Perhaps I overlook something. But my guess is that there is something overridden by the big datatype __int128. Maybe something can't deal with that type?
Can someone please help?
Unfortunately I was not able to even more shorten the code. (I know, in this form it makes little sense, but nevertheless it should execute correctly.)
#include <map>
#include <string>
#include <vector>
using namespace std;
#define ID_t unsigned __int128
struct __attribute__ ((packed)) DATA_t {
ID_t tid;
union {
array<uint16_t, 0> a;
uint8_t aDummy[4];
} data;
array<ID_t, 2> id;
};
template<class I>
class Entry {
public:
I data;
Entry<I>() {};
Entry<I>(const Entry<I>& orig) {};
virtual ~Entry<I>() {};
private:
};
template<class I>
struct ID_cmp {
bool operator()(const I& a, const I& b) const {
return a.id < b.id;
}
};
template<class I>
struct DATA_cmp {
bool operator()(const I& a, const I& b) const {
return a.data.a < b.data.a;
}
};
template<class I> class Index;
template<class I>
class IndexData {
public:
IndexData(Index<I>* index) : index(index) {};
IndexData(const IndexData<I>& orig) {};
virtual ~IndexData() {};
bool InsertOrFindEntry(Entry<I>** entry) {
if (!entries) {
entries = new map<I, Entry<I>*, DATA_cmp < I >> ();
Entry<I> modEntry;
modEntry.data = (*entry)->data;
index->CreateEntry(&modEntry.data);
}
auto search = entries->find((*entry)->data);
if (search == entries->end()) {
entries->operator[]((*entry)->data) = *entry;
return true;
} else {
delete *entry;
*entry = search->second;
return false;
}
};
Entry<I>* FindEntry(const I* data) {
if (entries) {
auto entry = entries->find(*data);
return entry == entries->end() ? nullptr : entry->second;
}
return nullptr;
};
void PushAllEntries(vector<Entry<I>*>& datas) {
if (entries) for (const auto& e : *entries) datas.push_back(e.second);
};
private:
Index<I>* index;
map<I, Entry<I>*, DATA_cmp<I>>* entries = nullptr;
};
template<class I>
class IndexID {
public:
IndexID(Index<I>* index) {
this->index = new IndexData<I>(index);
};
IndexID(const IndexID<I>& orig) {};
virtual ~IndexID() {};
bool InsertOrFindEntry(Entry<I>** entry) {
return index->InsertOrFindEntry(entry);
};
Entry<I>* FindEntry(const I* data) {
return index->FindEntry(data);
};
void PushAllEntries(vector<Entry<I>*>& datas) {
if (index) index->PushAllEntries(datas);
};
private:
IndexData<I>* index = nullptr;
};
class IndexCommon {
public:
IndexCommon() {};
IndexCommon(const IndexCommon& orig) {};
virtual ~IndexCommon() {};
virtual void SomeFunc(void* entry) {};
private:
};
template<class I>
class Index : public IndexCommon {
public:
Index() {};
Index(const Index<I>& orig) {};
virtual ~Index() {};
bool InsertOrGetEntry(Entry<I>** entry) {
IndexID<I>* indexID = GetIndexID(&(*entry)->data);
return indexID->InsertOrFindEntry(entry);
};
Entry<I>* CreateEntry(const void* data) {
Entry<I>* entry = new Entry<I>();
entry->data = *(I*) data;
if (InsertOrGetEntry(&entry)) SomeFuncCreate(entry);
return entry;
};
void FindAllByFirstID(const ID_t id, vector<Entry<I>*>& datas);
void SomeFuncCreate(Entry<I>* entry);
void SomeFunc(void* entry) override;
private:
map<I, IndexID<I>*, ID_cmp<I>> indexID;
IndexID<I>* GetIndexID(const I* data) {
auto search = indexID.find(*data);
if (search == indexID.end()) {
IndexID<I>* idxID = new IndexID<I>(this);
indexID[*data] = idxID;
return idxID;
}
return search->second;
};
};
template <class I>
inline void Index<I>::FindAllByFirstID(const ID_t uid, vector<Entry<I>*>& datas) {
DATA_t search;
search.id[0] = uid;
search.id[1] = 0;
auto lower = indexID.lower_bound(search);
search.id[1] = UINT64_MAX;
auto upper = indexID.upper_bound(search);
if (lower == indexID.end()) return;
for (auto it = lower; it != upper; ++it) (*it).second->PushAllEntries(datas);
}
template<class I>
inline void Index<I>::SomeFuncCreate(Entry<I>* entry) {
vector<Entry<I>*> datas;
FindAllByFirstID(entry->data.id[1], datas);
}
template<class I>
inline void Index<I>::SomeFunc(void* entry) {
vector<Entry<I>*> datas;
FindAllByFirstID(((Entry<I>*)entry)->data.id[1], datas);
}
int main(int argc, char** argv) {
Index<DATA_t> myIndex = Index<DATA_t>();
Entry<DATA_t>* myEntry = new Entry<DATA_t>();
myIndex.InsertOrGetEntry(&myEntry);
return 0;
}
I work with Netbeans 11.1 on Win10, with MSYS_NT-10.0-19041.
I tried to shorten the code as far as possible, commented out every function and so on. I hoped, I could encircle the problem but it didn't really work it. If I remove to much of the code it works. All in all the behaviour seems to me to be not comprehensible.

Is there a way to add elements to this vector?

I have a class Column.h, a template ColumnImpl.h and a Tab.h
class Column {
public:
Column() {}
virtual ~Column() {};
virtual string getType() = 0;
};
template <typename T> class ColumnImpl : public Column {
public:
ColumnImpl() : Column() {}
void addElem(const T& elem_to_add);
protected:
vector<T> _data;
};
class Tab {
public:
Tab();
~Tab() {};
template <typename S> void addElemToCol(const string & col_name, const S & data_to_add);
private:
map<string, shared_ptr<Column>> _columns;
};
What I would like to do now, is adding elements to the template vector inside ColumnImpl.h using the method addElem, and then recalling it inside addElemToCol.
To do that I've tried (inside addElemToCol):
if (this->colIsPresent(col_name)) {
const auto & it = _columns.find(col_name);
it->second.get().
}
But here I realized I don't have the addElem method... How can I solve this issue?
EDIT 1:
This is how I'm checking the type and adding it into the vector:
int data;
data_stream >> data;
if (!data_stream.fail()) {
if (target_database.tabIsPresent(tab_name)) {
target_database.addElemToColOfTab(tab_name, col_name, data);
}
This is a Database method:
template <typename D> void addElemToColOfTab(const string & tab_name, const string & col_name, const D& data_to_add) {
const auto & it_target_tab = _tables.find(tab_name);
it_target_tab->second.addElemToCol(col_name, data_to_add);
}
This is a Tab method:
template <typename S> void addElemToCol(const string & col_name, const S & data_to_add) {
if (this->colIsPresent(col_name)) {
const auto & it = _columns.find(col_name);
switch (Type2Int(it->second->getType())) {
case OptionInt: {
ColumnImpl<int>* p_int = dynamic_cast<ColumnImpl<int> *>(it->second.get());
if (p_int != nullptr) {
p_int->addElem(data_to_add);
}
break;
}
case OptionFloat: {...}
// [...] All the other Columns
}
}
}
And every class IntColumn, FloatColumn has its own implementation:
void addElem(const int& elem_to_add) { _data.push_back(elem_to_add); } // this is for IntColumn
You are getting this error because all of the switch blocks need to compile even if only one is taken. p_int->addElem(data_to_add); can only compile when the type of data_to_add matches the corresponding ColumnImpl template type, and that's only true in one of the cases.
Since you know what S is, you don't actually need to go through any of the type-checking hoops; you can eliminate the switch altogether and just look for ColumnImpl<S>. We can also have the function return a bool indicating whether adding the element was successful.
template <typename S>
bool addElemToCol(const string & col_name, const S & data_to_add) {
const auto & it = _columns.find(col_name);
if (it != _columns.end()) {
auto ci = dynamic_cast<ColumnImpl<S> *>(it->second.get());
if (ci != nullptr) {
ci->addElem(data_to_add);
return true;
}
}
return false;
}

dynamically call same named function with different return type

I have a situation here...
I want to design a Factory where I can call a function with same name and no parameters but return different data Types. Based on the SubClassName I need to instantiate the Object.
Need help or lead on any design pattern to follow?
EDIT:
An abstract pseudo code...
class parent{
public:
virtual string getName() = 0;
//some virtual function.. not sure how to design. As the return type is dynamic.
*** getValue(){}
};
class A : public parent{
int x;
public:
virtual string getName(){ return "A";}
virtual int getValue(){retun x;}
};
class B : public parent{
string s;
public:
virtual string getName(){ return "B";}
virtual string getValue(){ return s;}
};
void main(){
string callingClass = "B";
parent * arrayPtrs[2];
arrayPtrs[0] = new A;
arrayPtrs[1] = new B;
for (loop through array, through iterator i){
if(arrayPtrs[i]->getName == callingClass ){
cout<<arrayPtrs[i]->getValue;
}
}
}
In C++ a function can only have one return type at a time, and you cannot change that dynamically.
However - as suggested by #mch - you can use template specializations. Keep in mind though, that this method is not dynamic. Your functions will be generated at compile time.
If I understood your question correctly, maybe this can be of help.
class MyObject1
{
//...
};
class MyObject2
{
//...
};
template<typename T>
struct Factory
{
constexpr static T gen();
};
template<>
struct Factory<MyObject1>
{
constexpr static MyObject1 gen()
{
return MyObject1(/*... whatever parameters you see fit ...*/);
}
};
template<>
struct Factory<MyObject2>
{
constexpr static MyObject2 gen()
{
return MyObject2(/*... whatever parameters you see fit ...*/);
}
};
int main()
{
auto myObj = Factory<MyObject1>::gen();
return 0;
}
Although this method seems fairly useless to me. You could simply call the desired constructor instead of this.
But then again, I'm not sure if this is what you thought of. If I made any mistakes please feel free, to correct me. I'll try to edit my answer best as I can.
EDIT:
To keep the virtual functionality too, the only way I can think of is type erasure: see https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure
The closest I could get to what you've asked for is this:
#include <iostream>
#include <string>
#include <any>
class parent {
public:
// you can use this too but I think type checking is more handy
// see in main function
/* virtual std::string getName() const = 0; */
virtual std::any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual std::any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual std::any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << std::any_cast<callingClass::value_type>(arrayPtrs[i]->getValue()) << std::endl;
}
return 0;
}
I hope this one helps.
Note, that I used dynamic_cast to check the correct type. If you know a better solution, you can use that, too. But under these circumstances I couldn't think of any better.
EDIT2:
#include <iostream>
#include <string>
#include <tuple>
class some
{
using id = size_t;
template<typename T>
struct type { static void id() { } };
template<typename T>
static id type_id() { return reinterpret_cast<id>(&type<T>::id); }
template<typename T>
using decay = typename std::decay<T>::type;
template<typename T>
using none = typename std::enable_if<!std::is_same<some, T>::value>::type;
struct base
{
virtual ~base() { }
virtual bool is(id) const = 0;
virtual base *copy() const = 0;
} *p = nullptr;
template<typename T>
struct data : base, std::tuple<T>
{
using std::tuple<T>::tuple;
T &get() & { return std::get<0>(*this); }
T const &get() const& { return std::get<0>(*this); }
bool is(id i) const override { return i == type_id<T>(); }
base *copy() const override { return new data{get()}; }
};
template<typename T>
T &stat() { return static_cast<data<T>&>(*p).get(); }
template<typename T>
T const &stat() const { return static_cast<data<T> const&>(*p).get(); }
template<typename T>
T &dyn() { return dynamic_cast<data<T>&>(*p).get(); }
template<typename T>
T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); }
public:
some() { }
~some() { delete p; }
some(some &&s) : p{s.p} { s.p = nullptr; }
some(some const &s) : p{s.p->copy()} { }
template<typename T, typename U = decay<T>, typename = none<U>>
some(T &&x) : p{new data<U>{std::forward<T>(x)}} { }
some &operator=(some s) { swap(*this, s); return *this; }
friend void swap(some &s, some &r) { std::swap(s.p, r.p); }
void clear() { delete p; p = nullptr; }
bool empty() const { return p; }
template<typename T>
bool is() const { return p ? p->is(type_id<T>()) : false; }
template<typename T> T &&_() && { return std::move(stat<T>()); }
template<typename T> T &_() & { return stat<T>(); }
template<typename T> T const &_() const& { return stat<T>(); }
template<typename T> T &&cast() && { return std::move(dyn<T>()); }
template<typename T> T &cast() & { return dyn<T>(); }
template<typename T> T const &cast() const& { return dyn<T>(); }
template<typename T> operator T &&() && { return std::move(_<T>()); }
template<typename T> operator T &() & { return _<T>(); }
template<typename T> operator T const&() const& { return _<T>(); }
};
using any = some;
class parent {
public:
// you can use this too but I think type checking is more handy
/* virtual std::string getName() const = 0; */
virtual any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << arrayPtrs[i]->getValue()._<callingClass::value_type>() << std::endl;
}
return 0;
}
This snipped is in case you cannot use C++17 features, and is based on:
any class

What's the best way to implement AST using visitor pattern with return value?

I'm trying to implement a simple abstract syntax tree (AST) in C++ using the visitor pattern. Usually a visitor pattern does not handle return value. But in my AST there are expressions nodes which care about the return type and value of its children node. For example, I have a Node structure like this:
class AstNode
{
public:
virtual void accept(AstNodeVisitor&) = 0;
void addChild(AstNode* child);
AstNode* left() { return m_left; }
AstNode* right() { return m_right; }
...
private:
AstNode* m_left;
AstNode* m_right;
};
class CompareNode : public AstNode
{
public:
virtual void accept(AstNodeVisitor& v)
{
v->visitCompareNode(this);
}
bool eval(bool lhs, bool rhs) const
{
return lhs && rhs;
}
};
class SumNode : public AstNode
{
public:
virtual void accept(AstNodeVisitor& v)
{
v->visitSumNode(this);
}
int eval(int lhs, int rhs) const
{
return lhs + rhs;
}
};
class AstNodeVisitor
{
public:
...
bool visitCompareNode(CompareNode& node)
{
// won't work, because accept return void!
bool lhs = node.left()->accept(*this);
bool rhs = node.right()->accept(*this);
return node.eval(lhs, rhs);
}
int visitSumNode(Node& node)
{
// won't work, because accept return void!
int lhs = node.left()->accept(*this);
int rhs = node.right()->accept(*this);
return node.eval(lhs, rhs);
}
};
In this case both CompareNode and SumNode are binary operators but they rely on the return type of their children's visit.
As far as I can see to make it work, there are only 2 options:
accept can still return void, save the return value in a context object which is passed to each accept and visit function, and use them in the visit function, where I know what type to use. This should work but feels like a hack.
make AstNode a template, and accept function a none virtual, but return type depends on template parameter T.But if I do this, I no longer have a common AstNode* class and can't save any AstNode* in the children list.
for example:
template <typename T`>
class AstNode
{
public:
T accept(AstNodeVisitor&);
...
};
So is there a more elegant way to do this? This should be a fairly common problem for people implementing AST walking so I'd like to know what's the best practice.
Thanks.
The Visitor can have member that it can use to store result, something like:
class AstNodeVisitor
{
public:
void visitCompareNode(CompareNode& node)
{
node.left()->accept(*this); // modify b
bool lhs = b;
node.right()->accept(*this); // modify b
bool rhs = b;
b = node.eval(lhs, rhs);
}
void visitSumNode(Node& node)
{
node.left()->accept(*this); // modify n
int lhs = n;
node.right()->accept(*this); // modify n
int rhs = n;
n = node.eval(lhs, rhs);
}
private:
bool b;
int n;
};
You may also want to save the type of last result or use something like boost::variant.
template<class T> struct tag { using type=T; };
template<class...Ts> struct types { using type=types; }
template<class T>
struct AstVisitable {
virtual boost::optional<T> accept( tag<T>, AstNodeVisitor&v ) = 0;
virtual ~AstVisitable() {};
};
template<>
struct AstVisitable<void> {
virtual void accept( tag<void>, AstNodeVisitor&v ) = 0;
virtual ~AstVisitable() {};
};
template<class Types>
struct AstVisitables;
template<>
struct AstVisibables<types<>> {
virtual ~AstVisitables() {};
};
template<class T0, class...Ts>
struct AstVisitables<types<T0, Ts...>>:
virtual AstVisitable<T0>,
AstVisitables<types<Ts...>>
{
using AstVisitable<T0>::accept;
using AstVisitables<types<Ts...>>::accept;
};
using supported_ast_return_types = types<int, bool, std::string, void>;
class AstNode:public AstVisitables<supported_ast_return_types> {
public:
void addChild(AstNode* child);
AstNode* left() { return m_left.get(); }
AstNode* right() { return m_right.get(); }
private:
std::unique_ptr<AstNode> m_left;
std::unique_ptr<AstNode> m_right;
};
template<class types>
struct AstVisiablesFailAll;
template<>
struct AstVisiablesFailAll<> {
virtual ~AstVisiablesFailAll() {};
};
template<class T>
struct AstVisitableFailure : virtual AstVisitable<T> {
boost::optional<T> accept( tag<T>, AstNodeVisitor& ) override {
return {};
}
};
template<>
struct AstVisitableFailure<void> : virtual AstVisitable<void> {
void accept( tag<void>, AstNodeVisitor& ) override {
return;
}
};
template<class T0, class...Ts>
struct AstVisitablesFailAll<types<T0, Ts...>>:
AstVisitableFailure<T0>,
AstVisitableFailAll<types<Ts...>>
{
using AstVisitableFailure<T0>::accept;
using AstVisitableFailAll<types<Ts...>>::accept;
};
So now you can boost::optional<bool> lhs = node.left()->accept( tag<bool>, *this );, and from the state of lhs know if the left node can be evaluated in a bool context.
SumNode looks like this:
class SumNode :
public AstNode,
AstVisiablesFailAll<supported_ast_return_types>
{
public:
void accept(tag<void>, AstNodeVisitor& v) override
{
accept(tag<int>, v );
}
boost::optional<int> accept(tag<int>, AstNodeVisitor& v) override
{
return v->visitSumNode(this);
}
int eval(int lhs, int rhs) const {
return lhs + rhs;
}
};
and visitSumNode:
boost::optional<int> visitSumNode(Node& node) {
// won't work, because accept return void!
boost::optional<int> lhs = node.left()->accept(tag<int>, *this);
boost::optional<int> rhs = node.right()->accept(tag<int>, *this);
if (!lhs || !rhs) return {};
return node.eval(*lhs, *rhs);
}
The above assumes that visiting a+b in a void context is acceptable (like in C/C++). If it isn't, then you need a means for void visit to "fail to produce a void".
In short, accepting requires context, which also determines what type you expect. Failure is an empty optional.
The above uses boost::optional -- std::experimental::optional would also work, or you can roll your own, or you can define a poor man's optional:
template<class T>
struct poor_optional {
bool empty = true;
T t;
explicit operator bool() const { return !empty; }
bool operator!() const { return !*this; }
T& operator*() { return t; }
T const& operator*() const { return t; }
// 9 default special member functions:
poor_optional() = default;
poor_optional(poor_optional const&)=default;
poor_optional(poor_optional const&&)=default;
poor_optional(poor_optional &&)=default;
poor_optional(poor_optional &)=default;
poor_optional& operator=(poor_optional const&)=default;
poor_optional& operator=(poor_optional const&&)=default;
poor_optional& operator=(poor_optional &&)=default;
poor_optional& operator=(poor_optional &)=default;
template<class...Ts>
void emplace(Ts&&...ts) {
t = {std::forward<Ts>(ts)...};
empty = false;
}
template<class...Ts>
poor_optional( Ts&&... ts ):empty(false), t(std::forward<Ts>(ts)...) {}
};
which sucks, because it constructs a T even if not needed, but it should sort of work.
For completion sake I post the template version that is mentioned by the OP
#include <string>
#include <iostream>
namespace bodhi
{
template<typename T> class Beignet;
template<typename T> class Cruller;
template<typename T> class IPastryVisitor
{
public:
virtual T visitBeignet(Beignet<T>& beignet) = 0;
virtual T visitCruller(Cruller<T>& cruller) = 0;
};
template<typename T> class Pastry
{
public:
virtual T accept(IPastryVisitor<T>& visitor) = 0;
};
template<typename T> class Beignet : public Pastry<T>
{
public:
T accept(IPastryVisitor<T>& visitor)
{
return visitor.visitBeignet(*this);
}
std::string name = "Beignet";
};
template<typename T> class Cruller : public Pastry<T>
{
public:
T accept(IPastryVisitor<T>& visitor)
{
return visitor.visitCruller(*this);
}
std::string name = "Cruller";
};
class Confectioner : public IPastryVisitor<std::string>
{
public:
virtual std::string visitBeignet(Beignet<std::string>& beignet) override
{
return "I just visited: " + beignet.name;
}
virtual std::string visitCruller(Cruller<std::string>& cruller) override
{
return "I just visited: " + cruller.name;
}
};
}
int main()
{
bodhi::Confectioner pastryChef;
bodhi::Beignet<std::string> beignet;
std::cout << beignet.accept(pastryChef) << "\n";
bodhi::Cruller<std::string> cruller;
std::cout << cruller.accept(pastryChef) << "\n";
return 0;
}
Every pastry is a node and every visitor can implement its accepted return type. Having multiple visitor could visit the same pastry.

How to return different types from same function?

For study purpose, I make own Any type. I don't understand, how to return Type or Type * depending on the conditions. This is my sketch of class:
class any
{
public:
template<class T>
any(T & d)
{
data_container = new container_impl<T>(d);
}
template<class T>
any(T* d)
{
is_pointer = true;
data_container = new container_impl<T>(d);
}
bool check_is_pointer() const;
template<class T>
T a_cast(size_t id) const
{
auto real_id = data_container->get_id();
if (real_id != id)
{
//throw new exeption
}
return static_cast<container_impl<T>&>(*data_container).get_data();
}
private:
class abstract_container
{
public:
virtual ~abstract_container() { }
virtual size_t get_id() const = 0;
};
template<typename T>
class container_impl : public abstract_container
{
public:
container_impl(T const& value)
{
data = value;
id = type_id<T>();
pointer_data = nullptr;
}
container_impl(T const* value)
{
pointer_data = value;
id = type_id<T*>();
}
T get_data()
{
return data;
}
size_t get_id() const override
{
return id;
}
private:
T data;
T const* pointer_data;
size_t id;
};
abstract_container *data_container = nullptr;
bool is_pointer = false;
};
template<class T>
T any_cast(any const& obj)
{
size_t id = type_id<T>();
return obj.a_cast<T>(id);
}
template<class T>
T* any_cast(any const& obj)
{
size_t id = type_id<T>();
return obj.a_cast<T>(id);
}
As you can see, I would like to create two functions any_cast, which return different types.
You can't return different types. The way that Boost does it is actually with different signatures - note that the two different versions take different arguments. One takes a reference and the other takes a pointer.
template <typename T> // this one will try to cast your any down to T
T any_cast(any& ); // and return it if that succeeds, else throw
template <typename T> // this one will NOT throw, but will return
T* any_cast(any* ); // a pointer instead
Example usage of the two different functions:
any a = 5;
any_cast<double>(a); // throws
double* v = any_cast<double>(&a); // won't throw
assert(v == nullptr);
int* vi = any_cast<int>(&a); // succeeds
assert(*vi == 5);