c++c++11builder-patternpolicy-based-design

C++ policy objects and the builder pattern


I have some class Builder which builds an Object. I have plans to replace some of the Object's guts with policy objects, for example being able to set some container type Storage. Specifically, I'd like to use the Builder to set policy objects of the Object, falling back to some default if none are specified; off the top of my head, something like so:

class Builder {
public
    Builder();

    // ... builder methods

    template<typename S>
    Builder& storage() { Storage = S; }

    Object init() { return Object<Storage>(...); }

private:
    typedef std::vector Storage;
}

template<typename Storage>
class Object { ... }

Object o = Builder()
    .storage<std::list>()
    .init()

The crux of the question is: can I use a typedef as a sort of "template variable" so I can store a user defined template variable?

To provide some more context, the Builder has to support creating a fairly complicated Object from a json config file, delegating each key and its validation to an individual method. I have a static named constructor Builder::from_config(...) and a method Builder::load_config(...) that do that for me, but I want to support picking the policy object from the config file. Otherwise I would be fine with just adding templates to the Builder::init() method so I could pass my policy objects to the Object.


Solution

  • I don't understand what you exactly want but...

    The crux of the question is: can I use a typedef as a sort of "template variable" so I can store a user defined template variable?

    I don't think so; a type can be a template parameter, not a variable; so a typedef is a fixed entity and (as far I know) can't be changed.

    Moreover:

    typedef std::vector Storage;
    

    doesn't work because std::vector<int> is a type but std::vector isn't.

    But std::vector can be a template-template parameter.

    The best I can imagine, to help you, is a internal template struct Storage with a template-template parameter.

    The following is a compilable example

    #include <list>
    
    template <template <typename ...> class C>
    class Object
     { };
    
    class Builder 
     {
       private:
          template <template <typename...> class C>
          struct Storage
           { Object<C> init() { return Object<C>{}; } };
    
       public:
          Builder ()
           { }
    
          template <template <typename...> class C>
          Storage<C> & storage() { static Storage<C> ret{}; return ret; }
     };
    
    int main ()
     {
       auto o = Builder{}.storage<std::list>().init();
    
       static_assert(std::is_same<decltype(o), Object<std::list>>{}, "!");
     }