I was trying to follow a tutorial and I am stuck badly at implementing the fluent builder for the unique_ptr as well. Despite knowing that it is a type conversion thing and after inspecting the documentation I wasn't able to find a proper fix.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
using namespace std;
class HtmlBuilder;
struct HtmlElement
{
string name;
string text;
vector<HtmlElement> elements;
const size_t indent_size = 2;
HtmlElement() {}
HtmlElement(const string& name, const string& text) : name{ name }, text{ text }
{
}
string str(int indent = 0) const // it is a const because it doesn't change the inner elements of htmlelement
{
ostringstream oss;
string i(indent_size * indent, ' '); // repeating a character as many times as required.
oss << i << "<" << name << ">" << endl;
if (text.size() > 0)
oss << string(indent_size * (indent + 1), ' ') << text << endl;
// recursive call
for (const auto& e : elements)
oss << e.str(indent + 1);
oss << i << "</" << name << ">" << endl;
return oss.str();
}
static HtmlBuilder build(string root_name);
static unique_ptr<HtmlBuilder> create(string root_name);
};
struct HtmlBuilder
{
HtmlBuilder(string root_name)
{
root.name = root_name;
}
HtmlElement root; // we can not do anything without root
HtmlBuilder& add_child(string child_name, string child_text)
{
HtmlElement e{ child_name, child_text };
root.elements.emplace_back(e);
// it is a reference
return *this;
}
HtmlBuilder* add_child2(string child_name, string child_text)
{
HtmlElement e{ child_name, child_text };
// emplace_back will return a reference to element that was just created in the vector where as push_back does not return anything, so you could preform some chaining if you wanted
root.elements.emplace_back(e);
// it is a pointer
return this;
}
string str() const {
return root.str();
}
// let's you convert the builder to htmlelement.
// automatic conversion.
// it wil be converted only after the chaining has finished.
operator HtmlElement() { return root; }
/*B& operator= (const A& x) { return *this; }*/
//operator unique_ptr<HtmlElement>() {
// return root;
//}
};
// it had to be pasted here after definition of HtmlBuilder
HtmlBuilder HtmlElement::build(string root_name)
{
// it will get automatically converted to a html element due to
// automatic conversion.
return HtmlBuilder{ root_name };
}
unique_ptr<HtmlBuilder> HtmlElement::create(string root_name) {
return make_unique<HtmlBuilder>(root_name);
}
// Basically we want to create builder from HtmlElement itself
// and be able to add childs as many as we want and at the end
// it will still return an HtmlElement due to automatic conversion
// in this way we hide builder completely
int main()
{
HtmlBuilder builder{ "ul" };
builder.add_child("li", "hello")
.add_child("li", "world");
//HtmlElement e = builder;
// important: automatic conversion occurs only at the end, if the object itself is returned.
HtmlElement e = HtmlElement::build("ul").add_child("li", "test").add_child("li", "test2");
HtmlElement ee = HtmlElement::create("ul")->add_child2("li", "test")->add_child2("li", "test2");
cout << e.str() << endl;
getchar();
return 0;
}
The problem is at trying to use use this line: HtmlElement::create("ul")->add_child2("li", "test")->add_child2("li", "test2");
It throws the error as explained above. It says that cannot convert from 'HtmlBuilder *' to 'HtmlElement'. Tried several solution but given that I am a beginner in c++ I already lost a couple of days trying to fix it. I would appreciate any help.
Aucun commentaire:
Enregistrer un commentaire