簡體   English   中英

C ++功能和通用編程[帶有MySQL連接器示例]

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

我將使用MySQL連接器。 它們提供了訪問結果行的功能。 一些示例是getString(1)getInt(1)getDate(2) 括號內的數字與結果的索引有關。

因此,我必須使用以下代碼訪問此示例行: 'John', 'M', 34

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

我出於各種原因(主要是出於娛樂目的)嘗試通用編程。 但是,即使花了很多時間我也無法實現它,這真是令人失望。

我想要的最終結果:

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

此函數應調用相應的MySQL API。

盡管語法錯誤,但也很高興看到與下面類似的任何答案。

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

請不要建議使用for循環。 讓我們嘗試一些更通用,更實用的方法;-)

這對我有用:

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);
      }
};

用法示例:

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>();

工作代碼: http//ideone.com/6IpJ8q

首先,您需要編寫以下內容:

template<class T> T get( MySQLRow const& row, unsigned index);
template<>
int get<int>( MySQLRow const& row, unsigned index) { return connector.GetInt(index); }
// etc

然后,添加一些模板元編程工具:

template<class...>struct types{using type=types;};

上面的代碼可能被std::tuple<?>*代替了types<?> 也許。 但是無論如何,上面的內容更加清晰。

接下來,可以將其替換為C ++ 14的integral_sequence

template<unsigned...>struct indexes{using type=indexes;};
template<unsigned max, unsigned...is>struct make_indexes<max-1, max-1, is...>{};
template<unsigned...is>struct make_indexes<0,is...>:indexes<is...>{};
template<unsigned max>using make_indexes_t=typename make_indexes<max>::type;

最后,東西:

namespace details {
  template<unsigned... Is, class... Types>
  std::tuple< Types... >
  getResult( indexes<Is...>, types<Types...>, MySQLRow const& row ) {
    return { get<Types>( row, Is+1 )... };
  }
}

template<class... Types>
std::tuple<Types...>
getResult( MySQLRow const& row ) {
  return details::getResult( make_indexes_t<sizeof...(Ts)>{}, types<Types...>{}, row );
}

語法是:

getResult<int, double, std::string>( row );

假設您編寫了各種get函數,並將MySQLRow的類型固定為實際值,並假設第一行是1

  1. 創建一組函數Get重載,該重載實現與row的GetX方法的統一接口:

     #define DEFINE_GET_FOR_TYPE(Type, TypeName) \\ void Get(Type& arg, const MySQLRow& row, std::size_t index) \\ { \\ arg = row.Get##TypeName(index); \\ } DEFINE_GET_FOR_TYPE(int, Int) DEFINE_GET_FOR_TYPE(std::string, String) // ... 

    在這里,宏DEFINE_GET_FOR_TYPE用於創建必要的集合。

  2. 使用C ++ 14 std::index_sequencestd::make_index_sequence實現GetResult函數模板( 它們也可以在C ++ 11程序中實現 ):

     struct Iterate { Iterate(...) {} }; template <std::size_t... indices, typename... Types> void GetResultImpl(const MySQLRow& row, std::index_sequence<indices...>, Types&... args) { Iterate{(Get(args, row, indices + 1), 0)...}; } template <typename... Types> void GetResult(const MySQLRow& row, Types&... args) { GetResultImpl(row, std::make_index_sequence<sizeof...(Types)>(), args...); } 
  3. 使用GetResult函數模板從該行獲取值:

     std::string name; std::string sex; int age; GetResult(row, name, sex, age); 

現場演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM