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:
- 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
Widget
s from myWidgetManager
, but then I'd have to bind theWidgetMaker
'sstatic
functions to individual instances ofWidget
s, which seems like more overhead. What's best performance-wise? - 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?
2 Answers 2
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).
Consider using overload resolution to resolve the proper logging-method.
- That allows you to template that member, and maybe use perfect forwarding.
Don't make useless costly copies. You can take arguments by
const&
.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&&) {}
};
Your
WidgetMaker
is currently restricted to policies which are templates. That's a bad idea. Better accept a type-parameter like everyone else.doAll
assumes the logging-method is static. Why then do you assign it to astd::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.