рд╡рд┐рдЬрд┐рдЯрд░ рдкреИрдЯрд░реНрди рдбреЗрдЯрд╛ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдПрд▓реНрдЧреЛрд░рд┐рдердо рдХреЛ рдбреЗрдЯрд╛ рд╕реЗ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдФрд░ рддрд░реАрдХрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдореВрд▓ рдкреИрдЯрд░реНрди рдХреЗ рдкреАрдЫреЗ рдХреЗ рд╡рд┐рдЪрд╛рд░, рдЗрд╕рдХреА C ++ рд╡рд┐рд╢рд┐рд╖реНрдЯ рднрд┐рдиреНрдирддрд╛, рдФрд░ рдЙрдкрдпреЛрдЧ рдХреЗ рдХреБрдЫ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг рдмрддрд╛рдКрдВрдЧрд╛ред
рдЖрдЧрдВрддреБрдХ
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЖрдЗрдП рдпрд╛рдж рдХрд░реЗрдВ рдХрд┐ рдХреНрд▓рд╛рд╕рд┐рдХ
рд╡рд┐рдЬрд╝рд┐рдЯрд░ рдХреИрд╕реЗ
рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ ред рдЗрд╕ рдкреИрдЯрд░реНрди рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрд░рдгрд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИред рдХрд▓реНрдкрдирд╛ рдХреАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ рд╣рдореЗрдВ рдмрд╣реБрд░реВрдкрд┐рдпреЛрдВ рдХреЗ рдПрдХ рдХрдВрдЯреЗрдирд░ (рдкреЗрдбрд╝, рдЧреНрд░рд╛рдл) рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд╡рд╕реНрддреБ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕рдВрдЪрд╛рд▓рди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдпрд╣ рд╕реЗрдЯ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд╕реНрд╡рдпрдВ рдЙрдиреНрд╣реЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдЬрд╛рдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рд╣реИрдВрдбрд▓рд░ рдЙрдиреНрд╣реЗрдВ "рджреЗрдЦ рд╕рдХрддрд╛ рд╣реИ"ред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдлрд╝рд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдСрдмреНрдЬреЗрдХреНрдЯ: рдлрд╝рд╛рдЗрд▓, рдлрд╝реЛрд▓реНрдбрд░:
class abstract_file_t { public: virtual std::string name() const = 0; virtual void accept(visitor_t& v) = 0; virtual ~abstract_file_t(){} };
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдлрд╝рд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬреНрдЮрд╛рди рдХрд┐ рд╡реЗ рдЙрдирдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рдХрд╛рдо рдХрд░реЗрдВрдЧреЗ, рдХреЗрд╡рд▓ рдЗрд╕ рддрдереНрдп рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ рдХрд┐ рдЖрдзрд╛рд░
рд╡рд┐рдЬрд╝рд┐рдЯрд░_рдЯ рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рд╛рде рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ
рдЙрдиреНрд╣реЗрдВ "рд╡рд┐рдЬрд╝рд┐рдЯ"
рдХрд░ рд╕рдХрддрд╛ рд╣реИ ред
рд╕реНрд╡реАрдХрд╛рд░ рд╕рдорд╛рд░реЛрд╣ рдореЗрдВ, рд╣рдо рдмрд╕ "рдЖрдЧрдВрддреБрдХ рдХреЛ рдЕрдВрджрд░ рдЖрдиреЗ рджреЗрддреЗ рд╣реИрдВ":
void regular_file_t::accept(visitor_t& v) {v.visit(*this);}
рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЗрд╕рдореЗрдВ рд╕рднреА рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ "рд╡рд┐рдЬрд╝рд┐рдЯ" рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреЛрдб рдЬреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
"рдЖрдЧрдВрддреБрдХ" рдХреА рд╡реНрдпрд╡рд╕реНрдерд╛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
class visitor_t { public: virtual void visit(regular_file_t& f) = 0; virtual void visit(directory_t& dir) = 0; virtual ~visitor_t(){} }; class print_info_visitor_t : public visitor_t { public: void visit(regular_file_t& f); { std::cout << "visiting concrete file. file name: " << f.name() << " file size: " << f.size() << std::endl; } void visit(directory_t& dir) { std::cout << "visiting directory. directory name: " << dir.name() << ". contains " << dir.files().size() << тАЬfilesтАЭ << std::endl; } };
рд╕реНрдереИрддрд┐рдХ рдЖрдЧрдВрддреБрдХ
рд╕реНрдЯреЗрдЯрд┐рдХ рд╡рд┐рдЬрд╝рд┐рдЯрд░ рдХрд╛ рд╕рд╛рд░ рднреА рдЗрд╕ рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрд▓реНрдЧреЛрд░рд┐рджрдо рд╕реЗ рдбреЗрдЯрд╛ рдХреЛ рдЕрд▓рдЧ рдХрд░рдиреЗ рдореЗрдВ рдирд┐рд╣рд┐рдд рд╣реИред рдореБрдЦреНрдп рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рдХреНрд▓рд╛рд╕рд┐рдХ
рд╡рд┐рдЬрд╝рд┐рдЯрд░ рдХреЗ рдЧрддрд┐рд╢реАрд▓ рдмрд╣реБрд░реВрдкрддрд╛ рдХреЛ рд╕реНрдерд┐рд░ (рдЗрд╕рд▓рд┐рдП рдореБрд╣рд╛рд╡рд░реЗ рдХрд╛ рдирд╛рдо) рдХреЗ рд╕рд╛рде рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЬрдм рд╣рдо
рдПрд╕рдЯреАрдПрд▓ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╣рдо рд▓рдЧрднрдЧ рд╣рд░ рдмрд╛рд░ рдЗрд╕ рдкреИрдЯрд░реНрди рдХреЗ рдПрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рддреЗ рд╣реИрдВред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ,
STL рд╡рд┐рдзреЗрдп рдПрдХ
рд╕реНрдерд┐рд░ рдЖрдЧрдВрддреБрдХ рдХрд╛ рдПрдХ рдмреЗрд╣рддрд░реАрди рдЙрджрд╛рд╣рд░рдг рд╣реИред рдЗрд╕реЗ рдХрд╛рдлреА рд╕реНрдкрд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЫреЛрдЯреЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:
class person_t { public: person_t(const std::string& name, size_t age) : name_(name), age_(age){} template<typename Visitor> void accept(Visitor& v) {v.visit(*this);} size_t age() const {return age_;} private: std::string name_; size_t age_; };
рдкрд╣рд▓реЗ рдЕрдзреНрдпрд╛рдп рдореЗрдВ рд╣рдордиреЗ рдЬреЛ рджреЗрдЦрд╛, рд╡рд╣ рдмрд╣реБрдд рд╣рдж рддрдХ рд╡реИрд╕рд╛ рд╣реА рд╣реИ?
рдЙрдкрдпреЛрдЧ рдХреЗ рдЙрджрд╛рд╣рд░рдг
рдЧреНрд░рд╛рдл рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЛ рдмрдврд╝рд╛рд╡рд╛ рджреЗрдирд╛
рдПрдХ рд╡рд┐рдзреЗрдп рдХрд╛ рд╡рд┐рдЪрд╛рд░ рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП "рд╡рд┐рдЬрд╝рд┐рдЯрд░" рдХреА рдорджрдж рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдХреБрдЫ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдВрджреБрдУрдВ рдкрд░ рд╣рдорд╛рд░реЗ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдХреНрдпреЛрдВ рдирд╣реАрдВ рджреА рдЬрд╛рддреА рд╣реИ? рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдо рдЗрди рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдиреЛрдбреНрд╕ рдФрд░ рдХрд┐рдирд╛рд░реЛрдВ рдФрд░ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рднрдВрдбрд╛рд░рдг рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рд╕реЗ рдорд┐рд▓рдХрд░ рд░реЗрдЦрд╛рдВрдХрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд▓рд┐рдЦрддреЗ рд╣реИрдВ (
рдмреВрд╕реНрдЯ рдЧреНрд░рд╛рдл рд▓рд╛рдЗрдмреНрд░реЗрд░реА )ред рдЕрдзрд┐рдХрддрдо рд▓рдЪреАрд▓реЗрдкрди рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рджреЛ рд╕рдВрд╕реНрдХрд░рдг рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдПрдХ рдЬреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИ рдФрд░ рджреВрд╕рд░рд╛ рд╡рд╣ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рдХреБрдЫ рдЪрд░рдгреЛрдВ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рд╕рд░рд▓реАрдХреГрдд, рдпрд╣ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
template<typename T> struct node_t { node_t(){}
рдПрд▓реНрдЧреЛрд░рд┐рджрдоред рдПрдХ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕рдВрд╕реНрдХрд░рдг рдФрд░ рдПрдХ рдЖрдЧрдВрддреБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ
template<typename T, typename Graph> void generate_graph(Graph& g, size_t size); template<typename T, typename Graph, typename Visitor> void generate_graph(Graph& g, Visitor& v, size_t size) { for(size_t i = 0; i < size; ++i) { node_t<T> node; node.on_init(v); g.push_back(node); } }
рдЕрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛрдбред
struct person_t { std::string name; int age; };
рдкреНрд░рдХрд╛рд░
рд╕реНрдереИрддрд┐рдХ рдЖрдЧрдВрддреБрдХ рдореБрд╣рд╛рд╡рд░реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдФрд░ рдмреЗрд╣рдж рджрд┐рд▓рдЪрд╕реНрдк рдЙрджрд╛рд╣рд░рдг
рдмрдврд╝рд╛рд╡рд╛ рдореЗрдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
:: рд╕рдВрд╕реНрдХрд░рдг ред
рд╡реЗрд░рд┐рдПрдВрдЯ рдПрдХ рд╕реНрдЯреЗрдЯрд┐рдХрд▓реА рдЯрд╛рдЗрдкреНрдб
рдпреВрдирд┐рдпрди рд╣реИ ред рдХрд┐рд╕реА рднреА рдорд╛рдиреНрдп рдкреНрд░рдХрд╛рд░ рдХрд╛ рдбреЗрдЯрд╛ рдЙрд╕реА рдмрд╛рдЗрдЯ рд╕рд░рдгреА рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдФрд░ рд╣рдо "рд╡рд┐рдЬрд╝рд┐рдЯ" рдХрд░рддреЗ рд╣реИрдВ, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдореЗрд╢рд╛ рдпрд╣ рд╕рд░рдгреА рд╣рдореЗрд╢рд╛
рд╡реЗрд░рд┐рдПрдВрдЯ рдХреЗ рдЕрдВрджрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддреА рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ рдЗрд╕реЗ рд╣рд░ рдмрд╛рд░ "рджреЗрдЦрддреЗ рд╣реИрдВ"ред рдЖрдк рдЗрд╕реЗ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдХреЛрдб рдпрдерд╛рд╕рдВрднрд╡ рд╕рд░рд▓ рд╣реИ рдФрд░ рдХреЗрд╡рд▓ рдореБрдЦреНрдп рд╡рд┐рдЪрд╛рд░ рдмрддрд╛рддрд╛ рд╣реИ):
template< typename T1 = default_param1, typename T2 = default_param2, typename T3 = default_param3 > class variant { ... public:
рд▓рд╛рдЧреВ рдлрд╝рдВрдХреНрд╢рди рдЗрд╕ рддрд░рд╣ рджрд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ
template<typename Visitor, typename U> void apply1( const Visitor& v, U u, typename std::enable_if< !std::is_same<U, default_param1>::value>::type* = 0) {
рдпрд╣рд╛рдВ рд╣рдо SFINAE рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд░реНрддрдорд╛рди рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рд╕рд╣реА рдлрд╝рдВрдХреНрд╢рди рдХреЛ "рд╕рдХреНрд╖рдо" рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд╡рд░реНрдЧ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд▓рд┐рдП "рдЕрдХреНрд╖рдо" рдХрд░рддреЗ рд╣реИрдВред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛрдб рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ:
struct visitor_t { void operator()(int i)const ; void operator()(double d)const; void operator()(const std::string& s)const; }; variant<int, double> test_v(34); test_v.apply_visitor(visitor_t());