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);
}
Quonux
  • 2,975
  • 1
  • 24
  • 32
Craig Wright
  • 1,575
  • 1
  • 11
  • 19

1 Answers1

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>;
nosid
  • 48,932
  • 13
  • 112
  • 139
  • 1
    @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. – nosid Jun 07 '12 at 13:27
  • 1
    @KerrekSB Welcome to C++, where no one uses the same syntax for anything ;) – R. Martinho Fernandes Jun 07 '12 at 14:07
  • 2
    I only see it focus on "auto". That's even worse. – Johannes Schaub - litb Jun 07 '12 at 14:45
  • 1
    We need a new syntax for variables, too: `auto n = 10 -> long int;` – Kerrek SB Jun 07 '12 at 15:08
  • 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. – nosid Jun 07 '12 at 15:35
  • 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. – David Stone Nov 18 '13 at 01:50