#include <iostream>
#include <utility>
#include <memory>
#include <vector>
#include <stdexcept>
class element
{
public:
element() = default;
virtual ~element() = default;
element(std::string value)
: value_{ std::move(value) }
{
}
auto value() const -> const std::string&
{
return value_;
}
virtual const element& child(std::size_t i) const
{
throw std::runtime_error("Invalid child index.");
}
virtual void print(std::ostream& out, int level) const
{
out << std::string(level * 2, ' ')
<< "<element>" << value() << "</element>";
}
private:
std::string value_;
};
auto operator<<(std::ostream& out, const element& e) -> std::ostream&
{
e.print(out, 0);
return out;
}
class group : public element
{
public:
template <typename... Children>
group(Children&&... children)
{
append(std::forward<Children>(children)...);
}
template <typename... Children>
void append(Children&&... children)
{
(
children_.emplace_back(
std::make_unique<Children>(std::forward<Children>(children))
),
...
);
}
virtual const element& child(std::size_t i) const override
{
if (i >= children_.size())
throw std::runtime_error("Invalid child index.");
return *children_[i];
}
virtual void print(std::ostream& out, int level) const override
{
out << std::string(level * 2, ' ') << "<group>\n";
print_children(out, level + 1);
out << std::string(level * 2, ' ') << "</group>";
}
void print_children(std::ostream& out, int level) const
{
for (const auto& child : children_)
{
child->print(out, level);
out << "\n";
}
}
private:
std::vector<std::unique_ptr<element>> children_;
};
class document : public group
{
public:
template <typename... Children>
document(Children&&... children)
: group{ std::forward<Children>(children)... }
{
}
protected:
virtual void print(std::ostream& out, int level) const override
{
out << std::string(level * 2, ' ') << "<document>\n";
print_children(out, level + 1);
out << std::string(level * 2, ' ') << "</document>";
}
};
auto main() -> int
{
auto d = document{
group{
element{ "element1" },
element{ "element2" },
element{ "element3" }
},
group{
group{
element{ "element4" },
element{ "element5" },
element{ "element6" }
},
element{ "element7" }
}
};
d.append(
group{
element{ "element8" }
}
);
std::cout << "\nd --------------------------------------\n\n" << d << "\n";
std::cout << "\nd.child(1) -----------------------------\n\n"
<< d.child(1) << "\n";
std::cout << "\nd.child(1).child(0).child(2).value() ---\n\n"
<< d.child(1).child(0).child(2).value() << "\n\n";
}