c++templatespolicy-based-design

C++ policy design with variable data


There's quite a bit of info on this topic. This is more of a design question, but I will give examples.

Let's say that I literally want to pass around a profile class, that dictates policies of a user.

struct ApplicationAllowedPolicy
{
public:
    bool hasAccess() { return true; }
}

struct ApplicationProhibitedPolicy
{
public:
    bool hasAccess() { return false; }
}

template<typename ApplicationPolicy>
class Profile : private ApplicationPolicy
{
    bool hasAccess() { return ApplicationPolicy::access(); }
}

int main()
{
    Profile<ApplicationAllowedPolicy> allowed;
    Profile<ApplicationProhibitedPolicy> prohibited;

    // do something with allowed & prohibited
}

The above is all fine and dandy, but let's assume there are a lot of policies that need to be read in. 5 Seems like a realistic real world number, although it could be more. Then, let's assume that this profile will be applied to hundreds of instances, with the 5 policies varying greatly. To boot, the policy behavior would only be known at run time (read from file, db, whatever). This quickly becomes unscalable, unless I'm totally missing something.

I thought of doing a non-type template class as a policy.

template<int N>
struct ApplicationPolicy
{
    int policy = N;
};

Profile<ApplicationPolicy<1>> allowed;
Profile<ApplicationPolicy<0>> prohibited;

I think this would indeed work for my situation, but I'm wondering if this is missing the point of policy based design. I'm having problems seeing the pros of this over just have Profile be a normal struct, and just set it's data members to true/false as needed.

Thoughts?


Solution

  • Policy-based design is very useful when the behaviour of the class changes significantly depending on a policy. For example, say you want your class to be used both in multithreaded and regular context. Then you could implement this as a threading policy:

    class SingleThreadedPolicy { /* ... */ }; // lock() does nothing
    class MultiThreadedPolicy { /* ... */ }; // lock() actually locks
    
    template<class T, class ThreadingPolicy>
    class Queue {
        ThreadingPolicy threadPol_;
        // ...
        T pop() {
           threadPol_.lock();
           // remove an element from the queue
           threadPol_.unlock();
           return element;
        }
    };
    

    Now, two other ways to achieve the same result is to use (multiple?) inheritance or to set a flag in the object and write a lot of ifs. The first option quickly breaks down if you have several policies, such as storage, ownership, etc. The second leads to unmaintainable code.

    So, if your class needs many orthogonal moving parts, policy-based design is a good choice, and it will be much more scalable than other approaches.

    However, your example does not really seem to need this approach. Access seems to be integral to it: if you are going to call hasAccess() in your code anyway, you can safely replace it with a boolean variable.