Policy class design but without making the whole user class a template

后端 未结 3 358
悲哀的现实
悲哀的现实 2021-01-15 05:28

Consider the following code where the Writer_I acts as an interface. Other classes which fulfil the contract of writing element types in correct form can derive

3条回答
  •  说谎
    说谎 (楼主)
    2021-01-15 05:44

    Your design constraint is that Calculator needs to not be a template, and has to be initialized with a writer.

    That means its interface with the writer has to be dynamic. It can be through a virtual interface class, by storing function pointers, or by being passed pointers later, or similar.

    As you don't want the polymorphic interface of writer to be fixed, that rules out a virtual interface.

    Now, we can do this manually.

    void header() {
      for (int i = 0; i < 10; i++) {
        write_i(i);
      }
    }
    
    void footer() {
      write_i(-100.0f);
    }
    

    those are the calls we need to type erase. We need to type erase down to their signatures, and remember how to do it later.

    template
    struct tag_t { using type=T; };
    template
    constexpr tag_t tag = {};
    
    template
    struct any_type_erase;
    template
    struct any_type_erase {
      std::function operation;
    
      any_type_erase() = default;
      any_type_erase(any_type_erase const&) = default;
      any_type_erase(any_type_erase &&) = default;
      any_type_erase& operator=(any_type_erase const&) = default;
      any_type_erase& operator=(any_type_erase &&) = default;
    
      template
      any_type_erase(tag_t, F&& f) {
        operation = [f=std::forward(f)](Any& object, Args&&...args)->R {
          return f(*std::any_cast(&object), std::forward(args)...);
        };
      }
    
      R operator()(Any& any, Args...args)const {
        return operation(any, std::forward(args)...);
      }
    };
    

    any_type_erase is a bit of a helper to do the boxing of the operation. For a const operation, pass in std::any const as the 2nd argument.

    Add these members:

    std::any writer;
    any_type_erase print_header;
    any_type_erase print_footer;
    
    template
    static auto invoke_writer() {
      return [](auto& writer, auto&&..args) {
        writer.write(decltype(args)(args)...);
      };
    }
    
    template
    Calculator(Writer_I& writer) :
      writer(writer),
      print_header( tag>, invoke_writer() ),
      print_footer( tag>, invoke_writer() )
    {}
    
    void header() {
      for (int i = 0; i < 10; i++) {
        print_header( writer, i );
      }
    }
    
    void footer() {
      print_footer( writer, -100.0f );
    }
    

提交回复
热议问题