Policy Based Design with Variadic Templates
Asked Answered
B

1

5

I have a set of homogeneous policy classes that I want to pass as policies to a template class, PolicyDrivenClass, which takes some unknown number of policy template parameters.

Each policy implements a "name" function, and I would like to be able to query the names of all of the policies at run time via PolicyDriveClass::getNames.

I have a working implementation, but it feels clunky, especially given that in my final design the Policy classes will implement several functions similar to "name", though perhaps with different return types, and that my Policy Driven Class will want to provide accessors similar to "getNames" for each of these functions.

My question is whether anyone can come up with a better implementation for this.

For what it's worth I'm using clang++. My version of g++ does not like this.

Here's what I have so far:

#include <string>
#include <deque>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;

template<typename... Policies>
class PolicyDrivenClass
{
   public:

      template<typename T, typename... Types>
      class NameExtractor
      {
         public:
            static deque<string> getNames() 
            {
               deque<string> names = NameExtractor<Types...>::getNames();
               names.push_front(T::name());
               return names;
            }

      };
      template<typename T>
      class NameExtractor<T>
      {
         public:
            static deque<string> getNames() 
            {
               deque<string> ret;
               ret.push_back(T::name());
               return ret;
            }
      };

      deque<string> getNames() const
      {
         return NameExtractor<Policies...>().getNames();
      }
};

class Policy1
{
   public:
      static string name(){return "policy 1";}
};

class Policy2
{
   public:
      static string name(){return "policy 2";}
};

class Policy3
{
   public:
      static string name(){return "policy 3";}
};



int main()
{
   PolicyDrivenClass<Policy1, Policy2, Policy3> c;
   deque<string> names = c.getNames();

   ostream_iterator<string> out (cerr,"\n");
   copy(names.begin(), names.end(), out);
}
Bourse answered 7/6, 2012 at 12:59 Comment(3)
Your policies (here) are stateless, do you expect to have stateful policies at some point or not ? (might get a bit more difficult).Plication
Correction. The code above does work with g++. There were some things I was doing before that did not work.Bourse
I do not expect stateful policies at this point, but I could see where that might get difficult.Bourse
Y
7

You are right. There are easier ways to get the list of names. The following works with GCC-4.7:

template <typename ...Policies>
struct PolicyDrivenClass
{
    std::deque<std::string> getNames() const 
    {
        return { Policies::name()... };
    }
};

Edit: Changed the declaration part of the function to the old syntax. Personally, I prefer the new syntax:

    auto getNames() const -> std::deque<std::string>;
Ylem answered 7/6, 2012 at 13:12 Comment(6)
@KerrekSB: It's only about readability. IMO the new syntax improves readability because you can focus on the most important information - the name of the function.Ylem
@KerrekSB Welcome to C++, where no one uses the same syntax for anything ;)Indisputable
I only see it focus on "auto". That's even worse.Yoohoo
We need a new syntax for variables, too: auto n = 10 -> long int;Hipbone
We are used to the syntax with the (return) type on the left side, because the commonly used programming languages with static typing use this syntax. But was it the right choice in the beginning? There are a few programming languages, that put the type on the other side, e.g. function getName(): String and var n:Int = 10 in Pascal. Newer languages also use this syntax, e.g. Scala. And I expect to the the new syntax more often in the near future.Ylem
The new syntax also has the benefit of being self-consistent. You can always use a trailing return type; you cannot always use the "old style" syntax.Mulvihill

© 2022 - 2024 — McMap. All rights reserved.