,
hiererchy,
, :
template<class Parent, class Child = void> struct chain;
: , :
struct base
{ ... virtual void reset(); ... };
struct child : base
{ ... virtual void reset(); ... };
struct grandchild : child
{ ... virtual void reset(); ... };
struct great_grandchild : grandchild
{ ... virtual void reset(); ... };
struct great_great_grandchild : great_grandchild
{ ... virtual void reset(); ... };
:
struct base
{ ... virtual void reset(); ... };
struct child : chain<base>
{ ... virtual void reset(); ... };
struct grandchild : chain<base,child>
{ ... virtual void reset(); ... };
struct great_grandchild : chain<child,grandchild>
{ ... virtual void reset(); ... };
struct great_great_grandchild : chain<grandchild,great_grandchild>
{ ... virtual void reset(); ... };
, ,
.
- ,
"" - - - -
chain<P> chain<P,C>, C -
P.
, chain<grandchild,child> of great_grandchild,
,
reset. grandchild, child
- great_grandchild.
, great_grandchild this->grandchild::reset()
this->child::reset(), child.
chain<T>: :
struct child : chain<base> { ... };
chain
#include <type_traits>
namespace detail {
template<class ...> using void_t = void;
template<class, class = void >
struct has_base_type : std::false_type {};
template<class T >
struct has_base_type<T,void_t<typename T::base_type>> : std::true_type
{
using type = typename T::base_type;
};
template<class T>
using has_base_type_t = typename has_base_type<T>::type;
template<class T>
struct has_real_base
{
static constexpr bool value = has_base_type<T>::value &&
!std::is_same<has_base_type_t<T>,T>::value;
};
template<class Parent, class Child = void>
struct chain : virtual Parent, virtual Child
{
using base_type = Parent;
using child_type = Child;
template<class T>
static std::enable_if_t<has_real_base<T>::value>
recurse(chain * const pd) {
pd->base_type::base_type::reset();
}
template<class T>
static std::enable_if_t<!has_real_base<T>::value>
recurse(chain * const pd) {}
void reset() override {
this->child_type::reset();
this->base_type::reset();
recurse<base_type>(this);
}
virtual ~chain() = default;
};
template<class T>
struct chain<T> : virtual T
{
using base_type = T;
void reset() override {
this->base_type::reset();
}
virtual ~chain() = default;
};
}
template<class Parent, class Child = void>
struct chain : detail::chain<Parent,Child>
{
using base_type = detail::chain<Parent,Child>;
void reset() override {
this->base_type::reset();
}
virtual ~chain() = default;
};
:
#include <iostream>
#include <memory>
struct base
{
virtual void reset() {
std::cout << "calling base::reset()\n";
}
virtual ~base() = default;
};
struct child : virtual chain<base>
{
void reset() override {
std::cout << "calling child::reset()\n";
}
virtual ~child() = default;
};
struct grandchild : chain<base,child>
{
void reset() override {
std::cout << "calling grandchild::reset()\n";
}
virtual ~grandchild() = default;
};
struct great_grandchild : chain<child,grandchild>
{
void reset() override {
std::cout << "calling great_grandchild::reset()\n";
}
virtual ~great_grandchild() = default;
};
struct great_great_grandchild : chain<grandchild,great_grandchild>
{
void reset() override {
std::cout << "calling great_great_grandchild::reset()\n";
}
virtual ~great_great_grandchild() = default;
};
using namespace std;
int main()
{
cout << "obj1\n";
shared_ptr<base> obj1 = make_shared<chain<base,child>>();
obj1->reset();
cout << "\n";
cout << "obj2\n";
shared_ptr<base> obj2 = make_shared<chain<child,grandchild>>();
obj2->reset();
cout << "\n";
cout << "obj3\n";
shared_ptr<base> obj3 = make_shared<chain<grandchild,great_grandchild>>();
obj3->reset();
cout << "\n";
cout << "obj4\n";
shared_ptr<base> obj4 =
make_shared<chain<great_grandchild,great_great_grandchild>>();
obj4->reset();
cout << "\n";
cout << "obj5\n";
shared_ptr<grandchild> obj5 = make_shared<chain<grandchild,great_grandchild>>();
obj5->reset();
cout << "\n";
cout << "obj6\n";
shared_ptr<base> obj6 = make_shared<chain<grandchild>>();
obj6->reset();
}
outpout:
obj1
calling child::reset()
calling base::reset()
obj2
calling grandchild::reset()
calling child::reset()
calling base::reset()
obj3
calling great_grandchild::reset()
calling grandchild::reset()
calling child::reset()
calling base::reset()
obj4
calling great_great_grandchild::reset()
calling great_grandchild::reset()
calling grandchild::reset()
calling child::reset()
calling base::reset()
obj5
calling great_grandchild::reset()
calling grandchild::reset()
calling child::reset()
calling base::reset()
obj6
calling grandchild::reset()
, obj5 , -
base - reset :
base::reset().
Note that in the case obj6, calling resetthe dynamic type on the object chain<P>, and not chain<P,C>, suppresses recursion: this is equivalent to a call P::reset().
A further problem of supporting several chain functions in each of the hierarchical classes is collapsing into a support problem, since any other member functions can be called. also the problem of passing arguments to chain functions is reduced to the problem of passing a tuple of arguments to one chain function.
(g ++ 5.1 / clang ++ 3.6, C ++ 14, trivially adaptable to C ++ 11)