Search code examples
c++templatesfunctional-programminggeneric-programming

C++ functional & generic programming [with MySQL connector example]


I am going to use MySQL connector. They provide functions to access the result row. Some examples are getString(1), getInt(1), getDate(2). The number inside the parenthesis is about the index of the result.

So that I have to use the following code to access this example row: 'John', 'M', 34

string name = row.getString(1);
string sex = row.getString(2);
int age = row.getInt(3);

I would like to try generic programming for various reasons (mainly for fun). But it was quite disappointing that I can't make it happens even with much time used.

The final result that I want:

std::tie<name, sex, age> = row.getResult<string, string, int>();

This functions should call the corresponding MySQL API.

It is also good to see any answer similar to below, although the syntax is wrong.

std::tie<name, sex, age> = row.getResult([string, string, int]);

Please don't suggest using for-loop. Let's try something more generic & functional ;-)


Solution

  • This works for me:

    struct Row
    {
       template <int N, typename ... Args> struct Helper;
    
       template <typename Arg1> struct Helper<1, Arg1>
       {
          static std::tuple<Arg1> getResult(Row& r)
          {
             return std::make_tuple(r.getResult<Arg1>(0));
          }
       };
    
       template <int N, typename Arg1, typename ... Args>
          struct Helper<N, Arg1, Args...>
          {
             static std::tuple <Arg1, Args ...> getResult(Row& r)
             {
                return std::tuple_cat(std::make_tuple(r.getResult<Arg1>(N-1)),
                                      Helper<N-1, Args...>::getResult(r));
             }
          };
    
       template <typename Arg> Arg getResult(int index)
       {
          // This is where the value needs to be extracted from the row.
          // It is a dummy implementation for testing purposes.
          return Arg{};
       }
    
       template <typename ... Args>
          std::tuple <Args ...> getResult()
          {
             return Helper<sizeof...(Args), Args...>::getResult(*this);
          }
    };
    

    Example usage:

    Row r;
    auto res1 = r.getResult<std::string>();
    auto res2 = r.getResult<int>();
    auto res3 = r.getResult<int, double, int>();
    auto res4 = r.getResult<int, int, double, double>();
    auto res5 = r.getResult<std::string, std::string, int, int, double, double>();
    

    Working code: http://ideone.com/6IpJ8q