Thursday, September 27, 2012

c++11 Variadic template

Another interesting feature of c++11 is the variadic templates. Basically these allow you to add infinite, heterogeneous parameters to your functions. However their syntax seems to force you to define them recursively. As a result they seem to be usable in 2 main ways.

  1. Map: Apply an repeated operation over the entire list of objects
  2. Reduce(or fold): Take in the list of objects and compound them into something
How very Hadoop. This apparent limited usability makes them a prime candidate for reduction in a forwarding function. Something that simply recurses the list of parameters and forwards them through a normaliser into a Lambda or directly into a templated function that can handle the specific Type. Here is the Normalize and Lambda approach.
#include <iostream>
#include <sstream>
#include <functional>

template <typename R, typename I>
R normalise(I i)
{
  try
    {
      R item;
      std::stringstream s;
      s << i;
      s >> item;
      return item;
    }
  catch(...)
    {}

  return R();
}

template <typename R, typename I>
R reduce(std::function<R (const R&, const R&)> action, I i)
{
  return normalise<R>(i);
}

template <typename R, typename I, typename... II>
R reduce(std::function<R (const R&, const R&)> action, I i, II... ii)
{
  return action(normalise<R>(i), reduce<R>(action, ii...));
}

template <typename R, typename I>
R map(std::function<void (const R&)> action, I i)
{
  action(normalise<R>(i));
}

template <typename R, typename I, typename... II>
void map(std::function<void (const R&)> action, I i, II... ii)
{
  action(normalise<R>(i));
  map<R>(action, ii...);
}

int main()
{ 
  std::function<int (const int&, const int&)> max
    = [](const int& a, const int& b)->int { return a>b ? a : b;  };  

  std::function<float (const float&, const float&)> min
    = [](const float& a, const float& b)->float { return a<b ? a : b;  };  

  std::function<float (const float&, const float&)> sum
    = [](const float& a, const float& b)->float { return a+b;  };  

  std::cout << "Max:" << reduce(max, "452", 3.422, 32, 0x000000ff, "543.485") << "\n";
  std::cout << "Min:" << reduce(min, "452", 3.422, 32, 0x000000ff, "543.485") << "\n";
  std::cout << "Sum:" << reduce(sum, "452", 3.422, 32, 0x000000ff, "543.485") << "\n";

  float res = 0;
  std::function<void (const float&)> accum
    = [&res](const float& a) { res += a;  };  

  map(accum, "452", 3.422, 32, 0x000000ff, "543.485");
  
  std::cout << "\n" << "Accum:" << res << "\n";

  std::stringstream ss;
  std::function<void (const float&)> stream = [&ss](const float& a) { ss << a << ",";  };

  map(stream, "452", 3.422, 32, 0x000000ff, "543.485");
  std::cout << ss.str() << "\n";
}

No comments:

Post a Comment