From 08382ac53c1e5ba6dba8a5486cfb8c5a8019bf09 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Wed, 15 Oct 2014 21:34:21 +0200
Subject: [PATCH] add promoting visitor

---
 alib2data/src/alphabet/SymbolBase.h           |   4 +-
 alib2data/src/automaton/AutomatonBase.h       |   4 +-
 alib2data/src/automaton/FSM/CompactNFA.h      |   4 +
 alib2data/src/automaton/FSM/EpsilonNFA.h      |   3 +
 alib2data/src/automaton/FSM/ExtendedNFA.h     |   5 +
 .../src/automaton/FSM/MultiInitialStateNFA.h  |   2 +
 alib2data/src/automaton/FSM/NFA.cpp           |   1 -
 alib2data/src/automaton/FSM/NFA.h             |   2 +
 alib2data/src/container/ContainerBase.h       |   4 +-
 alib2data/src/grammar/GrammarBase.h           |   4 +-
 alib2data/src/label/LabelBase.h               |   4 +-
 alib2data/src/object/ObjectBase.h             |   4 +-
 alib2data/src/primitive/PrimitiveBase.h       |   4 +-
 alib2data/src/regexp/RegExpBase.h             |   4 +-
 .../src/regexp/formal/FormalRegExpElement.h   |   3 +-
 .../regexp/unbounded/UnboundedRegExpElement.h |   3 +-
 alib2data/src/std/visitor.hpp                 | 128 ++++++++--
 alib2data/src/string/StringBase.h             |   5 +-
 alib2data/test-src/std/StdVisitorTest.cpp     | 233 ++++++++++++++++++
 alib2data/test-src/std/StdVisitorTest.h       |  19 ++
 20 files changed, 406 insertions(+), 34 deletions(-)
 create mode 100644 alib2data/test-src/std/StdVisitorTest.cpp
 create mode 100644 alib2data/test-src/std/StdVisitorTest.h

diff --git a/alib2data/src/alphabet/SymbolBase.h b/alib2data/src/alphabet/SymbolBase.h
index ce062e65ae..18027e6451 100644
--- a/alib2data/src/alphabet/SymbolBase.h
+++ b/alib2data/src/alphabet/SymbolBase.h
@@ -13,7 +13,9 @@
 
 namespace alphabet {
 
-typedef std::acceptor_base<
+class SymbolBase;
+
+typedef std::acceptor_base<SymbolBase,
 			LabeledSymbol, BlankSymbol, BottomOfTheStackSymbol, EndSymbol
 	> VisitableSymbolBase;
 
diff --git a/alib2data/src/automaton/AutomatonBase.h b/alib2data/src/automaton/AutomatonBase.h
index 5442d018b1..ff3d4c3249 100644
--- a/alib2data/src/automaton/AutomatonBase.h
+++ b/alib2data/src/automaton/AutomatonBase.h
@@ -14,7 +14,9 @@
 
 namespace automaton {
 
-typedef std::acceptor_base<
+class AutomatonBase;
+
+typedef std::acceptor_base<AutomatonBase,
 			automaton::DFA, automaton::NFA, automaton::MultiInitialStateNFA, automaton::EpsilonNFA, automaton::CompactNFA, automaton::ExtendedNFA, automaton::DPDA, automaton::SinglePopDPDA, automaton::InputDrivenNPDA, automaton::VisiblyPushdownDPDA, automaton::VisiblyPushdownNPDA, automaton::RealTimeHeightDeterministicDPDA, automaton::RealTimeHeightDeterministicNPDA, automaton::NPDA, automaton::SinglePopNPDA, automaton::OneTapeDTM
 	> VisitableAutomatonBase;
 
diff --git a/alib2data/src/automaton/FSM/CompactNFA.h b/alib2data/src/automaton/FSM/CompactNFA.h
index 97941daacb..5a8a23a227 100644
--- a/alib2data/src/automaton/FSM/CompactNFA.h
+++ b/alib2data/src/automaton/FSM/CompactNFA.h
@@ -13,6 +13,10 @@
 #include "../common/SingleInitialState.h"
 #include "../common/InputAlphabet.h"
 #include "../../string/LinearString.h"
+#include "EpsilonNFA.h"
+#include "MultiInitialStateNFA.h"
+#include "NFA.h"
+#include "DFA.h"
 
 namespace automaton {
 
diff --git a/alib2data/src/automaton/FSM/EpsilonNFA.h b/alib2data/src/automaton/FSM/EpsilonNFA.h
index ad4f323aa8..348dead1da 100644
--- a/alib2data/src/automaton/FSM/EpsilonNFA.h
+++ b/alib2data/src/automaton/FSM/EpsilonNFA.h
@@ -15,6 +15,9 @@
 #include "../common/InputAlphabet.h"
 #include "../../alphabet/Symbol.h"
 #include "../../string/Epsilon.h"
+#include "MultiInitialStateNFA.h"
+#include "NFA.h"
+#include "DFA.h"
 
 namespace automaton {
 
diff --git a/alib2data/src/automaton/FSM/ExtendedNFA.h b/alib2data/src/automaton/FSM/ExtendedNFA.h
index 54db04aca6..6703e34da1 100644
--- a/alib2data/src/automaton/FSM/ExtendedNFA.h
+++ b/alib2data/src/automaton/FSM/ExtendedNFA.h
@@ -13,6 +13,11 @@
 #include "../common/SingleInitialState.h"
 #include "../common/InputAlphabet.h"
 #include "../../regexp/RegExp.h"
+#include "CompactNFA.h"
+#include "EpsilonNFA.h"
+#include "MultiInitialStateNFA.h"
+#include "NFA.h"
+#include "DFA.h"
 
 namespace automaton {
 
diff --git a/alib2data/src/automaton/FSM/MultiInitialStateNFA.h b/alib2data/src/automaton/FSM/MultiInitialStateNFA.h
index 830f166f36..e104ce8a51 100644
--- a/alib2data/src/automaton/FSM/MultiInitialStateNFA.h
+++ b/alib2data/src/automaton/FSM/MultiInitialStateNFA.h
@@ -14,6 +14,8 @@
 #include "../common/MultiInitialStates.h"
 #include "../common/InputAlphabet.h"
 #include "../../alphabet/Symbol.h"
+#include "NFA.h"
+#include "DFA.h"
 
 namespace automaton {
 
diff --git a/alib2data/src/automaton/FSM/NFA.cpp b/alib2data/src/automaton/FSM/NFA.cpp
index f5ca944190..f92be7d733 100644
--- a/alib2data/src/automaton/FSM/NFA.cpp
+++ b/alib2data/src/automaton/FSM/NFA.cpp
@@ -6,7 +6,6 @@
  */
 
 #include "NFA.h"
-#include "DFA.h"
 #include "../AutomatonException.h"
 #include <ostream>
 #include <sstream>
diff --git a/alib2data/src/automaton/FSM/NFA.h b/alib2data/src/automaton/FSM/NFA.h
index 24af23d31d..880ac3d3fd 100644
--- a/alib2data/src/automaton/FSM/NFA.h
+++ b/alib2data/src/automaton/FSM/NFA.h
@@ -15,6 +15,8 @@
 #include "../common/InputAlphabet.h"
 #include "../../alphabet/Symbol.h"
 
+#include "DFA.h"
+
 namespace automaton {
 
 /**
diff --git a/alib2data/src/container/ContainerBase.h b/alib2data/src/container/ContainerBase.h
index c9eb75c43d..66c2ab8905 100644
--- a/alib2data/src/container/ContainerBase.h
+++ b/alib2data/src/container/ContainerBase.h
@@ -13,7 +13,9 @@
 
 namespace container {
 
-typedef std::acceptor_base<
+class ContainerBase;
+
+typedef std::acceptor_base<ContainerBase,
 			container::ObjectsSet,
 			container::ObjectsVector,
 			container::ObjectsPair,
diff --git a/alib2data/src/grammar/GrammarBase.h b/alib2data/src/grammar/GrammarBase.h
index 502ac204be..9ad26cb132 100644
--- a/alib2data/src/grammar/GrammarBase.h
+++ b/alib2data/src/grammar/GrammarBase.h
@@ -14,7 +14,9 @@
 
 namespace grammar {
 
-typedef std::acceptor_base<
+class GrammarBase;
+
+typedef std::acceptor_base<GrammarBase,
 			grammar::LeftLG, grammar::LeftRG, grammar::RightLG, grammar::RightRG, grammar::LG, grammar::CFG, grammar::EpsilonFreeCFG, grammar::CNF, grammar::GNF, grammar::CSG, grammar::NonContractingGrammar, grammar::ContextPreservingUnrestrictedGrammar, grammar::UnrestrictedGrammar
 	> VisitableGrammarBase;
 
diff --git a/alib2data/src/label/LabelBase.h b/alib2data/src/label/LabelBase.h
index 58df68b672..1fea94675d 100644
--- a/alib2data/src/label/LabelBase.h
+++ b/alib2data/src/label/LabelBase.h
@@ -13,7 +13,9 @@
 
 namespace label {
 
-typedef std::acceptor_base<
+class LabelBase;
+
+typedef std::acceptor_base<LabelBase,
 			label::PrimitiveLabel, label::HexavigesimalLabel, label::ObjectLabel, label::LabelSetLabel, label::LabelPairLabel
 	> VisitableLabelBase;
 
diff --git a/alib2data/src/object/ObjectBase.h b/alib2data/src/object/ObjectBase.h
index 87acf1f8b2..0a99bd83e8 100644
--- a/alib2data/src/object/ObjectBase.h
+++ b/alib2data/src/object/ObjectBase.h
@@ -115,7 +115,9 @@ class Character;
 
 namespace alib {
 
-typedef std::acceptor_base<
+class ObjectBase;
+
+typedef std::acceptor_base<ObjectBase,
 			Void,
 			exception::AlibException,
 			automaton::DFA, automaton::NFA, automaton::MultiInitialStateNFA, automaton::EpsilonNFA, automaton::CompactNFA, automaton::ExtendedNFA, automaton::DPDA, automaton::SinglePopDPDA, automaton::InputDrivenNPDA, automaton::VisiblyPushdownDPDA, automaton::VisiblyPushdownNPDA, automaton::RealTimeHeightDeterministicDPDA, automaton::RealTimeHeightDeterministicNPDA, automaton::NPDA, automaton::SinglePopNPDA, automaton::OneTapeDTM,
diff --git a/alib2data/src/primitive/PrimitiveBase.h b/alib2data/src/primitive/PrimitiveBase.h
index 33866ca880..7a2dfe9a5f 100644
--- a/alib2data/src/primitive/PrimitiveBase.h
+++ b/alib2data/src/primitive/PrimitiveBase.h
@@ -13,7 +13,9 @@
 
 namespace primitive {
 
-typedef std::acceptor_base<
+class PrimitiveBase;
+
+typedef std::acceptor_base<PrimitiveBase,
 			primitive::String, primitive::Integer, primitive::Character
 	> VisitablePrimitiveBase;
 
diff --git a/alib2data/src/regexp/RegExpBase.h b/alib2data/src/regexp/RegExpBase.h
index db3ae48d4f..639c6f52a7 100644
--- a/alib2data/src/regexp/RegExpBase.h
+++ b/alib2data/src/regexp/RegExpBase.h
@@ -13,7 +13,9 @@
 
 namespace regexp {
 
-typedef std::acceptor_base<
+class RegExpBase;
+
+typedef std::acceptor_base<RegExpBase,
 			UnboundedRegExp, FormalRegExp
 	> VisitableRegExpBase;
 
diff --git a/alib2data/src/regexp/formal/FormalRegExpElement.h b/alib2data/src/regexp/formal/FormalRegExpElement.h
index ac25ee3184..e02d2d5382 100644
--- a/alib2data/src/regexp/formal/FormalRegExpElement.h
+++ b/alib2data/src/regexp/formal/FormalRegExpElement.h
@@ -25,11 +25,12 @@ class FormalRegExpEmpty;
 class FormalRegExpEpsilon;
 
 class UnboundedRegExpElement;
+class FormalRegExpElement;
 
 /**
  * Abstract class representing element in the regular expression. Can be operator or symbol.
  */
-class FormalRegExpElement : public std::acceptor_base<FormalRegExpAlternation, FormalRegExpConcatenation, FormalRegExpIteration, FormalRegExpSymbol, FormalRegExpEmpty, FormalRegExpEpsilon> {
+class FormalRegExpElement : public std::acceptor_base<FormalRegExpElement, FormalRegExpAlternation, FormalRegExpConcatenation, FormalRegExpIteration, FormalRegExpSymbol, FormalRegExpEmpty, FormalRegExpEpsilon> {
 protected:
 	/* 
 	 * Parent regexp contanining this instance of RegExpElement
diff --git a/alib2data/src/regexp/unbounded/UnboundedRegExpElement.h b/alib2data/src/regexp/unbounded/UnboundedRegExpElement.h
index c0ce6c8f9f..9d6ee37cec 100644
--- a/alib2data/src/regexp/unbounded/UnboundedRegExpElement.h
+++ b/alib2data/src/regexp/unbounded/UnboundedRegExpElement.h
@@ -25,11 +25,12 @@ class UnboundedRegExpEmpty;
 class UnboundedRegExpEpsilon;
 
 class FormalRegExpElement;
+class UnboundedRegExpElement;
 
 /**
  * Abstract class representing element in the regular expression. Can be operator or symbol.
  */
-class UnboundedRegExpElement : public std::acceptor_base<UnboundedRegExpAlternation, UnboundedRegExpConcatenation, UnboundedRegExpIteration, UnboundedRegExpSymbol, UnboundedRegExpEmpty, UnboundedRegExpEpsilon> {
+class UnboundedRegExpElement : public std::acceptor_base<UnboundedRegExpElement, UnboundedRegExpAlternation, UnboundedRegExpConcatenation, UnboundedRegExpIteration, UnboundedRegExpSymbol, UnboundedRegExpEmpty, UnboundedRegExpEpsilon> {
 protected:
 	/**
 	 * Parent regexp contanining this instance of RegExpElement
diff --git a/alib2data/src/std/visitor.hpp b/alib2data/src/std/visitor.hpp
index e70671a1fc..d65eecdfa8 100644
--- a/alib2data/src/std/visitor.hpp
+++ b/alib2data/src/std/visitor.hpp
@@ -2,8 +2,8 @@
  * Visitor.h
  *
  *  Created on: Apr 05, 2014
- *      Author: Andrew Durward
- *      Modified: Jan Travnicek
+ *	  Author: Andrew Durward
+ *	  Modified: Jan Travnicek
  */
 
 #ifndef VISITOR_H_
@@ -21,17 +21,17 @@ class visitor;
 template<typename T>
 class visitor<T> {
 public:
-    virtual void Visit(void*, const T &) = 0;
+	virtual void Visit(void*, const T &) = 0;
 };
 
 // specialization for multiple types
 template<typename T, typename... Types>
 class visitor<T, Types...> : public visitor<Types...> {
 public:
-    // promote the function(s) from the base class
-    using visitor<Types...>::Visit;
+	// promote the function(s) from the base class
+	using visitor<Types...>::Visit;
 
-    virtual void Visit(void*, const T &) = 0;
+	virtual void Visit(void*, const T &) = 0;
 };
 
 // Visitor template declaration
@@ -42,40 +42,126 @@ class const_visitor;
 template<typename T>
 class const_visitor<T> {
 public:
-    virtual void Visit(void*, const T &) const = 0;
+	virtual void Visit(void*, const T &) const = 0;
 };
 
 // specialization for multiple types
 template<typename T, typename... Types>
 class const_visitor<T, Types...> : public const_visitor<Types...> {
 public:
-    // promote the function(s) from the base class
-    using const_visitor<Types...>::Visit;
+	// promote the function(s) from the base class
+	using const_visitor<Types...>::Visit;
 
-    virtual void Visit(void*, const T &) const = 0;
+	virtual void Visit(void*, const T &) const = 0;
 };
 
 template<typename... Types>
+class const_promoting_helper;
+
+template<typename Tested, typename... Other>
+struct const_promoting_helper<Tested, Other...> {
+
+	template<class Desired, class Base, class TargetVisitor,
+			typename std::enable_if< std::is_constructible<Desired, Tested>::value >::type* = nullptr >
+	inline static bool tryPromote(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) {
+		if(dynamic_cast<const Tested*>(&second)) {
+			visitor.Visit(userData, first, Desired(dynamic_cast<const Tested&>(second)));
+			return true;
+		} else {
+			return const_promoting_helper<Other...>::tryPromote(userData, first, second, visitor);
+		}
+	}
+
+	template<class Desired, class Base, class TargetVisitor,
+			typename std::enable_if< ! std::is_constructible<Desired, Tested>::value >::type* = nullptr >
+	inline static bool tryPromote(void* userData, const Desired& first, const Base& second, const TargetVisitor& visitor) {
+		return const_promoting_helper<Other...>::tryPromote(userData, first, second, visitor);
+	}
+};
+
+template<> struct const_promoting_helper<>  {
+	template<class Desired, class Base, class TargetVisitor>
+	inline static bool tryPromote(void*, const Desired&, const Base&, const TargetVisitor&) { return false; }
+};
+
+// Visitor template declaration
+template<typename... Types>
+class const_promoting_visitor;
+
+// specialization for single type
+template<typename T>
+class const_promoting_visitor<T> {
+public:
+	virtual void Visit(void*, const T &, const T&) const = 0;
+
+	template<typename R, typename promoting_helper_type>
+	bool Visit1(void* userData, const T& first, const R& second) const {
+		return promoting_helper_type::tryPromote( userData, first, second, *this );
+	}
+};
+
+// specialization for multiple types
+template<typename T, typename... Types>
+class const_promoting_visitor<T, Types...> : public const_promoting_visitor<Types...> {
+public:
+	// promote the function(s) from the base class
+	using const_promoting_visitor<Types...>::Visit;
+	using const_promoting_visitor<Types...>::Visit1;
+
+	virtual void Visit(void*, const T &, const T&) const = 0;
+
+	template<typename R, typename promoting_helper_type>
+	bool Visit1(void* userData, const T& first, const R& second) const {
+		return promoting_helper_type::tryPromote( userData, first, second, *this );
+	}
+};
+
+template<typename T, typename... Types>
 class acceptor_base {
 public:
-    typedef visitor<Types...> visitor_type;
-    typedef const_visitor<Types...> const_visitor_type;
+	typedef visitor<Types...> visitor_type;
+
+	typedef const_visitor<Types...> const_visitor_type;
 
-    virtual void Accept(void* userData, visitor<Types...>& visitor) const = 0;
-    virtual void Accept(void* userData, const const_visitor<Types...>& visitor) const = 0;
+	typedef const_promoting_visitor<Types...> const_promoting_visitor_type;
+	typedef const_promoting_helper<Types...> const_promoting_helper_type;
+	typedef T base_type;
+
+	virtual void Accept(void* userData, visitor<Types...>& visitor) const = 0;
+
+	virtual void Accept(void* userData, const const_visitor<Types...>& visitor) const = 0;
+
+	virtual bool Accept(void* userData, const T& other, const const_promoting_visitor<Types...>& visitor) const = 0;
 };
 
-template<typename Derived, typename Visitor, typename Base>
+template<typename Derived, typename AcceptorBase, typename Base>
 class acceptor : public Base {
 public:
-    virtual void Accept(void* userData, typename Visitor::visitor_type& visitor) const {
-        visitor.Visit(userData, static_cast<const Derived&>(*this));
-    }
-    virtual void Accept(void* userData, const typename Visitor::const_visitor_type& visitor) const {
-        visitor.Visit(userData, static_cast<const Derived&>(*this));
-    }
+	virtual void Accept(void* userData, typename AcceptorBase::visitor_type& visitor) const {
+		visitor.Visit(userData, static_cast<const Derived&>(*this));
+	}
+	virtual void Accept(void* userData, const typename AcceptorBase::const_visitor_type& visitor) const {
+		visitor.Visit(userData, static_cast<const Derived&>(*this));
+	}
+
+	virtual bool Accept(void* userData, const typename AcceptorBase::base_type& other, const typename AcceptorBase::const_promoting_visitor_type& visitor) const {
+		return visitor.template Visit1<typename AcceptorBase::base_type, typename AcceptorBase::const_promoting_helper_type>(userData, static_cast<const Derived&>(*this), other);
+	}
 };
 
+
+template<class T, class R>
+void Accept(void* userData, const T& first, const T& second, const R& visitor) {
+	bool res;
+	res = first.Accept(userData, second, visitor);
+	if(res) return;
+
+	res = second.Accept(userData, first, visitor);
+	if(res) return;
+
+	throw std::logic_error("cant promote parameters");
+}
+
 } /* namespace std */
 
 #endif /* VISITOR_H_ */
diff --git a/alib2data/src/string/StringBase.h b/alib2data/src/string/StringBase.h
index 64ef5419e6..de7461bcde 100644
--- a/alib2data/src/string/StringBase.h
+++ b/alib2data/src/string/StringBase.h
@@ -13,7 +13,9 @@
 
 namespace string {
 
-typedef std::acceptor_base<
+class StringBase;
+
+typedef std::acceptor_base<StringBase,
 			string::Epsilon, string::LinearString, string::CyclicString
 	> VisitableStringBase;
 
@@ -27,7 +29,6 @@ public:
 
 	virtual StringBase* clone() const = 0;
 	virtual StringBase* plunder() && = 0;
-    
 };
 
 } /* namespace string */
diff --git a/alib2data/test-src/std/StdVisitorTest.cpp b/alib2data/test-src/std/StdVisitorTest.cpp
new file mode 100644
index 0000000000..314c3d0e13
--- /dev/null
+++ b/alib2data/test-src/std/StdVisitorTest.cpp
@@ -0,0 +1,233 @@
+#include "StdVisitorTest.h"
+#include "std/visitor.hpp"
+#include "common/base.hpp"
+#include <set>
+#include <string>
+
+CPPUNIT_TEST_SUITE_REGISTRATION( StdVisitorTest );
+
+void StdVisitorTest::setUp() {
+}
+
+void StdVisitorTest::tearDown() {
+}
+
+class Tmp1;
+class Tmp2;
+class Tmp3;
+
+class TmpBase;
+
+typedef std::acceptor_base<TmpBase,
+			Tmp1, Tmp2, Tmp3
+	> VisitableTmpBase;
+
+class TmpBase :
+	public alib::base<
+			TmpBase,
+			Tmp1, Tmp2, Tmp3
+	>, public VisitableTmpBase {
+};
+
+class Tmp1 : public std::acceptor<Tmp1, VisitableTmpBase, TmpBase> {
+	int data;
+public:
+	Tmp1(int data) : data(data) {
+	
+	}
+
+	TmpBase* clone() const {
+		return new Tmp1(*this);
+	}
+
+	TmpBase* plunder() && {
+		return new Tmp1(*this);
+	}
+
+	virtual bool operator<(const TmpBase& other) const {
+		return other > *this;
+	}
+
+	virtual bool operator==(const TmpBase& other) const {
+		return other == *this;
+	}
+
+	virtual bool operator>(const TmpBase& other) const {
+		return other < *this;
+	}
+
+	virtual bool operator==(const Tmp1& other) const {
+		return this->data == other.data;
+	}
+
+	virtual bool operator<(const Tmp1& other) const {
+		return this->data < other.data;
+	}
+
+	virtual void operator>>(std::ostream& os) const {
+		os << "Tmp1(" << data <<  ")";
+	}
+
+	virtual operator std::string() const {
+		return "Tmp1(" + std::to_string(data) + ")";
+	}
+
+	virtual int selfTypeId() const {
+		return typeId(*this);
+	}
+
+	int getData() const {
+		return data;
+	}
+
+};
+
+class Tmp2 : public std::acceptor<Tmp2, VisitableTmpBase, TmpBase> {
+	double data;
+public:
+	Tmp2(double data) : data(data) {
+	
+	}
+
+	Tmp2(const Tmp1& other) : data(other.getData()) {
+
+	}
+
+	TmpBase* clone() const {
+		return new Tmp2(*this);
+	}
+
+	TmpBase* plunder() && {
+		return new Tmp2(*this);
+	}
+
+	virtual bool operator<(const TmpBase& other) const {
+		return other > *this;
+	}
+
+	virtual bool operator==(const TmpBase& other) const {
+		return other == *this;
+	}
+
+	virtual bool operator>(const TmpBase& other) const {
+		return other < *this;
+	}
+
+	virtual bool operator==(const Tmp2& other) const {
+		return this->data == other.data;
+	}
+
+	virtual bool operator<(const Tmp2& other) const {
+		return this->data < other.data;
+	}
+
+	virtual void operator>>(std::ostream& os) const {
+		os << "Tmp2(" << data <<  ")";
+	}
+
+	virtual operator std::string() const {
+		return "Tmp2(" + std::to_string(data) + ")";
+	}
+
+	virtual int selfTypeId() const {
+		return typeId(*this);
+	}
+
+	double getData() const {
+		return data;
+	}
+
+};
+
+class Tmp3 : public std::acceptor<Tmp3, VisitableTmpBase, TmpBase> {
+	std::string data;
+public:
+	Tmp3(const std::string& data) : data(data) {
+	
+	}
+
+	Tmp3(const Tmp1& other) : data(std::to_string(other.getData())) {
+
+	}
+
+	Tmp3(const Tmp2& other) : data(std::to_string(other.getData())) {
+
+	}
+
+	TmpBase* clone() const {
+		return new Tmp3(*this);
+	}
+
+	TmpBase* plunder() && {
+		return new Tmp3(*this);
+	}
+
+	virtual bool operator<(const TmpBase& other) const {
+		return other > *this;
+	}
+
+	virtual bool operator==(const TmpBase& other) const {
+		return other == *this;
+	}
+
+	virtual bool operator>(const TmpBase& other) const {
+		return other < *this;
+	}
+
+	virtual bool operator==(const Tmp3& other) const {
+		return this->data == other.data;
+	}
+
+	virtual bool operator<(const Tmp3& other) const {
+		return this->data < other.data;
+	}
+
+	virtual void operator>>(std::ostream& os) const {
+		os << "Tmp3(" << data <<  ")";
+	}
+
+	virtual operator std::string() const {
+		return "Tmp3(" + data + ")";
+	}
+
+	virtual int selfTypeId() const {
+		return typeId(*this);
+	}
+
+	const std::string& getData() const {
+		return data;
+	}
+
+};
+
+class TmpVisitor : public VisitableTmpBase::const_promoting_visitor_type {
+	void Visit(void* userData, const Tmp1& first, const Tmp1& second) const {
+		int& data = *((int*) userData);
+		data = 1;
+		std::cout << first << " " << second << std::endl;
+	}
+
+	void Visit(void* userData, const Tmp2& first, const Tmp2& second) const {
+		int& data = *((int*) userData);
+		data = 2;
+		std::cout << first << " " << second << std::endl;
+	}
+
+	void Visit(void* userData, const Tmp3& first, const Tmp3& second) const {
+		int& data = *((int*) userData);
+		data = 3;
+		std::cout << first << " " << second << std::endl;
+	}
+};
+
+void StdVisitorTest::testPromoteVisitor() {
+	TmpVisitor visitor;
+
+	Tmp1 tmp1(2);
+	Tmp3 tmp3("3");
+
+	int a = 0;
+	Accept((void*) &a, (TmpBase&) tmp1, (TmpBase&) tmp3, visitor);
+
+	CPPUNIT_ASSERT(a == 3);
+}
diff --git a/alib2data/test-src/std/StdVisitorTest.h b/alib2data/test-src/std/StdVisitorTest.h
new file mode 100644
index 0000000000..da75d57781
--- /dev/null
+++ b/alib2data/test-src/std/StdVisitorTest.h
@@ -0,0 +1,19 @@
+#ifndef VISITOR_TEST_H_
+#define VISITOR_TEST_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class StdVisitorTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( StdVisitorTest );
+  CPPUNIT_TEST( testPromoteVisitor );
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+  void setUp();
+  void tearDown();
+
+  void testPromoteVisitor();
+};
+
+#endif  // VISITOR_TEST_H_
-- 
GitLab