Skip to main content
added 63 characters in body
Source Link
#include <iostream>
#include <memory>
#include <vector>

// Backported from C++14
namespace std
{
    template<typename T, typename ...Args>
    std::unique_ptr<T> make_unique(Args &&... args)
    {
        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
}

using namespace std;

class Widget
{
    Widget() = delete;
    Widget(Widget const &) = delete;
    Widget(Widget &&) = delete;
    Widget &operator=(Widget const &) = delete;
    Widget &operator=(Widget &&) = delete;

public:
    Widget(string const &name) :
        m_name(name)
    { }

    ~Widget()
    { };

    string const &name() const
    { return m_name; }

private:
    string const m_name;
};

class WidgetBuilder
{
    WidgetBuilder(WidgetBuilder const &) = delete;
    WidgetBuilder(WidgetBuilder &&) = delete;
    WidgetBuilder &operator=(WidgetBuilder const &) = delete;
    WidgetBuilder &operator=(WidgetBuilder &&) = delete;

public:
    WidgetBuilder()
    { }

    ~WidgetBuilder()
    { };

    WidgetBuilder &name(string const &name)
    { m_name = name; return *this; }

    unique_ptr<Widget> create()
    { return make_unique<Widget>(m_name); }

private:
    string m_name;
};

class WidgetContainer
{
    WidgetContainer() = delete;
    WidgetContainer(WidgetContainer const &) = delete;
    WidgetContainer(WidgetContainer &&) = delete;
    WidgetContainer &operator=(WidgetContainer const &) = delete;
    WidgetContainer &operator=(WidgetContainer &&) = delete;

public:
    WidgetContainer(
        string const &firstName,
        string const &lastName,
        unique_ptr<vector<unique_ptr<Widget>>> widgets) :
        m_firstName(firstName),
        m_lastName(lastName),
        m_widgets(move(widgets))
    { }

    ~WidgetContainer()
    { };

    string const &firstName() const
    { return m_firstName; }

    string const &lastName() const
    { return m_lastName; }

    vector<unique_ptr<Widget>> const &widgets() const
    { return *m_widgets; }

private:
    string const m_firstName;
    string const m_lastName;
    unique_ptr<vector<unique_ptr<Widget>>> m_widgets;
};


class WidgetContainerBuilder
{
    WidgetContainerBuilder(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder(WidgetContainerBuilder &&) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder &&) = delete;

public:
    WidgetContainerBuilder()
    { }

    ~WidgetContainerBuilder()
    { };

    WidgetContainerBuilder &firstName(string const &firstName)
    { m_firstName = firstName; return *this; }

    WidgetContainerBuilder &lastName(string const &lastName)
    { m_lastName = lastName; return *this; }

    WidgetContainerBuilder &addWidget(WidgetBuilder &widgetBuilder)
    {
        m_widgetBuilders.push_back(&widgetBuilder);
        return *this;
    }

    unique_ptr<WidgetContainer> create()
    {
        unique_ptr<vector<unique_ptr<Widget>>> widgets =
            make_unique<vector<unique_ptr<Widget>>>();
        for (auto &widgetBuilder : m_widgetBuilders)
        {
            widgets->push_back(widgetBuilder->create());
        }
        return make_unique<WidgetContainer>(
            m_firstName,
            m_lastName,
            move(widgets));
    }

private:
    string m_firstName;
    string m_lastName;
    vector<WidgetBuilder *> m_widgetBuilders;
};

int main(int argc, char *argv[])
{
    unique_ptr<WidgetContainer> x(
        WidgetContainerBuilder()
            .firstName("my-first-name")
            .lastName("my-last-name")
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-0"))
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-1"))
            .create());

    cout << x->firstName() << " " << x->lastName() << endl;
    for (auto &widget : x->widgets())
    {
        cout << widget->name() << endl;
    }

    return 0;
}
#include <iostream>
#include <memory>
#include <vector>

// Backported from C++14
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args &&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

using namespace std;

class Widget
{
    Widget(Widget const &) = delete;
    Widget(Widget &&) = delete;
    Widget &operator=(Widget const &) = delete;
    Widget &operator=(Widget &&) = delete;

public:
    Widget(string const &name) :
        m_name(name)
    { }

    ~Widget()
    { };

    string const &name() const
    { return m_name; }

private:
    string const m_name;
};

class WidgetBuilder
{
    WidgetBuilder(WidgetBuilder const &) = delete;
    WidgetBuilder(WidgetBuilder &&) = delete;
    WidgetBuilder &operator=(WidgetBuilder const &) = delete;
    WidgetBuilder &operator=(WidgetBuilder &&) = delete;

public:
    WidgetBuilder()
    { }

    ~WidgetBuilder()
    { };

    WidgetBuilder &name(string const &name)
    { m_name = name; return *this; }

    unique_ptr<Widget> create()
    { return make_unique<Widget>(m_name); }

private:
    string m_name;
};

class WidgetContainer
{
    WidgetContainer(WidgetContainer const &) = delete;
    WidgetContainer(WidgetContainer &&) = delete;
    WidgetContainer &operator=(WidgetContainer const &) = delete;
    WidgetContainer &operator=(WidgetContainer &&) = delete;

public:
    WidgetContainer(
        string const &firstName,
        string const &lastName,
        unique_ptr<vector<unique_ptr<Widget>>> widgets) :
        m_firstName(firstName),
        m_lastName(lastName),
        m_widgets(move(widgets))
    { }

    ~WidgetContainer()
    { };

    string const &firstName() const
    { return m_firstName; }

    string const &lastName() const
    { return m_lastName; }

    vector<unique_ptr<Widget>> const &widgets() const
    { return *m_widgets; }

private:
    string const m_firstName;
    string const m_lastName;
    unique_ptr<vector<unique_ptr<Widget>>> m_widgets;
};


class WidgetContainerBuilder
{
    WidgetContainerBuilder(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder(WidgetContainerBuilder &&) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder &&) = delete;

public:
    WidgetContainerBuilder()
    { }

    ~WidgetContainerBuilder()
    { };

    WidgetContainerBuilder &firstName(string const &firstName)
    { m_firstName = firstName; return *this; }

    WidgetContainerBuilder &lastName(string const &lastName)
    { m_lastName = lastName; return *this; }

    WidgetContainerBuilder &addWidget(WidgetBuilder &widgetBuilder)
    {
        m_widgetBuilders.push_back(&widgetBuilder);
        return *this;
    }

    unique_ptr<WidgetContainer> create()
    {
        unique_ptr<vector<unique_ptr<Widget>>> widgets =
            make_unique<vector<unique_ptr<Widget>>>();
        for (auto &widgetBuilder : m_widgetBuilders)
        {
            widgets->push_back(widgetBuilder->create());
        }
        return make_unique<WidgetContainer>(
            m_firstName,
            m_lastName,
            move(widgets));
    }

private:
    string m_firstName;
    string m_lastName;
    vector<WidgetBuilder *> m_widgetBuilders;
};

int main(int argc, char *argv[])
{
    unique_ptr<WidgetContainer> x(
        WidgetContainerBuilder()
            .firstName("my-first-name")
            .lastName("my-last-name")
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-0"))
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-1"))
            .create());

    cout << x->firstName() << " " << x->lastName() << endl;
    for (auto &widget : x->widgets())
    {
        cout << widget->name() << endl;
    }

    return 0;
}
#include <iostream>
#include <memory>
#include <vector>

// Backported from C++14
namespace std
{
    template<typename T, typename ...Args>
    std::unique_ptr<T> make_unique(Args &&... args)
    {
        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
}

using namespace std;

class Widget
{
    Widget() = delete;
    Widget(Widget const &) = delete;
    Widget(Widget &&) = delete;
    Widget &operator=(Widget const &) = delete;
    Widget &operator=(Widget &&) = delete;

public:
    Widget(string const &name) :
        m_name(name)
    { }

    ~Widget()
    { }

    string const &name() const
    { return m_name; }

private:
    string const m_name;
};

class WidgetBuilder
{
    WidgetBuilder(WidgetBuilder const &) = delete;
    WidgetBuilder(WidgetBuilder &&) = delete;
    WidgetBuilder &operator=(WidgetBuilder const &) = delete;
    WidgetBuilder &operator=(WidgetBuilder &&) = delete;

public:
    WidgetBuilder()
    { }

    ~WidgetBuilder()
    { }

    WidgetBuilder &name(string const &name)
    { m_name = name; return *this; }

    unique_ptr<Widget> create()
    { return make_unique<Widget>(m_name); }

private:
    string m_name;
};

class WidgetContainer
{
    WidgetContainer() = delete;
    WidgetContainer(WidgetContainer const &) = delete;
    WidgetContainer(WidgetContainer &&) = delete;
    WidgetContainer &operator=(WidgetContainer const &) = delete;
    WidgetContainer &operator=(WidgetContainer &&) = delete;

public:
    WidgetContainer(
        string const &firstName,
        string const &lastName,
        unique_ptr<vector<unique_ptr<Widget>>> widgets) :
        m_firstName(firstName),
        m_lastName(lastName),
        m_widgets(move(widgets))
    { }

    ~WidgetContainer()
    { }

    string const &firstName() const
    { return m_firstName; }

    string const &lastName() const
    { return m_lastName; }

    vector<unique_ptr<Widget>> const &widgets() const
    { return *m_widgets; }

private:
    string const m_firstName;
    string const m_lastName;
    unique_ptr<vector<unique_ptr<Widget>>> m_widgets;
};


class WidgetContainerBuilder
{
    WidgetContainerBuilder(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder(WidgetContainerBuilder &&) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder &&) = delete;

public:
    WidgetContainerBuilder()
    { }

    ~WidgetContainerBuilder()
    { }

    WidgetContainerBuilder &firstName(string const &firstName)
    { m_firstName = firstName; return *this; }

    WidgetContainerBuilder &lastName(string const &lastName)
    { m_lastName = lastName; return *this; }

    WidgetContainerBuilder &addWidget(WidgetBuilder &widgetBuilder)
    {
        m_widgetBuilders.push_back(&widgetBuilder);
        return *this;
    }

    unique_ptr<WidgetContainer> create()
    {
        unique_ptr<vector<unique_ptr<Widget>>> widgets =
            make_unique<vector<unique_ptr<Widget>>>();
        for (auto &widgetBuilder : m_widgetBuilders)
        {
            widgets->push_back(widgetBuilder->create());
        }
        return make_unique<WidgetContainer>(
            m_firstName,
            m_lastName,
            move(widgets));
    }

private:
    string m_firstName;
    string m_lastName;
    vector<WidgetBuilder *> m_widgetBuilders;
};

int main(int argc, char *argv[])
{
    unique_ptr<WidgetContainer> x(
        WidgetContainerBuilder()
            .firstName("my-first-name")
            .lastName("my-last-name")
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-0"))
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-1"))
            .create());

    cout << x->firstName() << " " << x->lastName() << endl;
    for (auto &widget : x->widgets())
    {
        cout << widget->name() << endl;
    }

    return 0;
}
edited tags; edited title
Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

C++ builder Builder/named argument/fluent interface pattern with unique_ptr

Source Link

C++ builder/named argument/fluent interface pattern with unique_ptr

I'm trying to figure out the cleanest way to implement a fluent interface with unique_ptr and other "modern" C++ language constructs. Here's my first attempt:

#include <iostream>
#include <memory>
#include <vector>

// Backported from C++14
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args &&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

using namespace std;

class Widget
{
    Widget(Widget const &) = delete;
    Widget(Widget &&) = delete;
    Widget &operator=(Widget const &) = delete;
    Widget &operator=(Widget &&) = delete;

public:
    Widget(string const &name) :
        m_name(name)
    { }

    ~Widget()
    { };

    string const &name() const
    { return m_name; }

private:
    string const m_name;
};

class WidgetBuilder
{
    WidgetBuilder(WidgetBuilder const &) = delete;
    WidgetBuilder(WidgetBuilder &&) = delete;
    WidgetBuilder &operator=(WidgetBuilder const &) = delete;
    WidgetBuilder &operator=(WidgetBuilder &&) = delete;

public:
    WidgetBuilder()
    { }

    ~WidgetBuilder()
    { };

    WidgetBuilder &name(string const &name)
    { m_name = name; return *this; }

    unique_ptr<Widget> create()
    { return make_unique<Widget>(m_name); }

private:
    string m_name;
};

class WidgetContainer
{
    WidgetContainer(WidgetContainer const &) = delete;
    WidgetContainer(WidgetContainer &&) = delete;
    WidgetContainer &operator=(WidgetContainer const &) = delete;
    WidgetContainer &operator=(WidgetContainer &&) = delete;

public:
    WidgetContainer(
        string const &firstName,
        string const &lastName,
        unique_ptr<vector<unique_ptr<Widget>>> widgets) :
        m_firstName(firstName),
        m_lastName(lastName),
        m_widgets(move(widgets))
    { }

    ~WidgetContainer()
    { };

    string const &firstName() const
    { return m_firstName; }

    string const &lastName() const
    { return m_lastName; }

    vector<unique_ptr<Widget>> const &widgets() const
    { return *m_widgets; }

private:
    string const m_firstName;
    string const m_lastName;
    unique_ptr<vector<unique_ptr<Widget>>> m_widgets;
};


class WidgetContainerBuilder
{
    WidgetContainerBuilder(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder(WidgetContainerBuilder &&) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder const &) = delete;
    WidgetContainerBuilder &operator=(WidgetContainerBuilder &&) = delete;

public:
    WidgetContainerBuilder()
    { }

    ~WidgetContainerBuilder()
    { };

    WidgetContainerBuilder &firstName(string const &firstName)
    { m_firstName = firstName; return *this; }

    WidgetContainerBuilder &lastName(string const &lastName)
    { m_lastName = lastName; return *this; }

    WidgetContainerBuilder &addWidget(WidgetBuilder &widgetBuilder)
    {
        m_widgetBuilders.push_back(&widgetBuilder);
        return *this;
    }

    unique_ptr<WidgetContainer> create()
    {
        unique_ptr<vector<unique_ptr<Widget>>> widgets =
            make_unique<vector<unique_ptr<Widget>>>();
        for (auto &widgetBuilder : m_widgetBuilders)
        {
            widgets->push_back(widgetBuilder->create());
        }
        return make_unique<WidgetContainer>(
            m_firstName,
            m_lastName,
            move(widgets));
    }

private:
    string m_firstName;
    string m_lastName;
    vector<WidgetBuilder *> m_widgetBuilders;
};

int main(int argc, char *argv[])
{
    unique_ptr<WidgetContainer> x(
        WidgetContainerBuilder()
            .firstName("my-first-name")
            .lastName("my-last-name")
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-0"))
            .addWidget(
                WidgetBuilder()
                    .name("my-widget-1"))
            .create());

    cout << x->firstName() << " " << x->lastName() << endl;
    for (auto &widget : x->widgets())
    {
        cout << widget->name() << endl;
    }

    return 0;
}

The requirements of the design is that the fully constructed objects of the WidgetContainer and Widget "final" types should be immutable: properties of these classes must only be settable during construction and unchangeable thereafter. In order to construct instances of these classes, I've written WidgetContainerBuilder and WidgetBuilder. The other constraint is that I need to be able to manage the lifetimes of the final types using unique_ptr.

The example I give here works and has no obvious bugs, as far as I can tell. However, I would be interested in feedback about potential issues or approaches I might take to improve the cleanliness or fluency of the API.