4
\$\begingroup\$

I have been learning C++ for the past few weeks, and I made my first try with policy classes. Ultimately my goal is to use policy classes to manufacture wrapper classes on an std::vector. Part of what the wrapper class does is generate a custom allocator class that depends on the policy classes.

That's the inspiration for what I have below, which is a widget maker that makes widgets with a printing function that depends on the templated inputs.

Printing policy classes:

template <class T>
struct Chatty
{
  static void logVal(T val){
    std::cout << val << std::endl;
  }
  static void logS(std::string s){
    std::cout << s << std::endl;
  }
};

template <class T>
struct Silent
{
  static void logVal(T val){}
  static void logS(std::string s){}
};

Widget:

class Widget {
public:
  int x;
  int y;
  std::function<void(std::string)> print;
  Widget()
    :x(0), y(0), print([](std::string){})
  {};
};

WidgetManager:

template < template <class Created> class CreationPolicy, template <class Created> class LoggingPolicy>
class WidgetManager : public CreationPolicy<Widget>, public LoggingPolicy<Widget>
{
public:
  WidgetManager() {};
  static Widget* doAll(){
    Widget* w = WidgetManager::Create();
    std::function<void(std::string)> f1 = WidgetManager::logS;
    w->print = WidgetManager::logS;
    return w;
  }
};

I would appreciate feedback on all aspects of the code, but I also have two specific questions:

  1. My biggest concern: is there a better way to assign functions to the Widgets I am making? For example, perhaps I could directly assign member functions of Widgets from my WidgetManager, but then I'd have to bind the WidgetMaker's static functions to individual instances of Widgets, which seems like more overhead. What's best performance-wise?
  2. I am sure WidgetManager::doAll() is not the way to go, but I am struggling to find another way to call functions from various policies all together. What's a better way to do this?
\$\endgroup\$
3
\$\begingroup\$

In Widget, the members x and y should be private. They should not be exposed to the interface in such a way. You can either add the private keyword above them, or just move the public keyword below them (members are private by default, so both are essentially the same).

\$\endgroup\$
2
\$\begingroup\$
  1. Consider using overload resolution to resolve the proper logging-method.

    • That allows you to template that member, and maybe use perfect forwarding.
  2. Don't make useless costly copies. You can take arguments by const&.

  3. Avoid std::endl, as constant flushing also flushes any chance of good performance down the drain.

struct Chatty {
    template<class T>
    static void log(T&& t) { std::cout << std::forward<T>(t) << '\n'; }
};
struct Silent {
    template<class T>
    static void log(T&&) {}
};
  1. Your WidgetMaker is currently restricted to policies which are templates. That's a bad idea. Better accept a type-parameter like everyone else.

  2. doAll assumes the logging-method is static. Why then do you assign it to a std::function? (Yes, that function should have a signature avoiding copies, but that's a separate problem.)

    The easiest way to repair that is using a lambda. Or you can get fancy with SFINAE and maybe also allow the policy-class to only implement those parts it wants to override.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.