【问题标题】:Creating Generic Insert function创建通用插入函数
【发布时间】:2017-08-01 17:49:16
【问题描述】:

我试图创建可以获取表名和值并将插入返回到查询中的通用函数,并提出了如下内容:

    struct any {
  enum type {Int, Float, String};
  any(int   e) { m_data.INT    = e; m_type = Int;}
  any(float e) { m_data.FLOAT  = e; m_type = Float;}
  any(char* e) { m_data.STRING = e; m_type = String;}
  type get_type() const { return m_type; }
  int get_int() const { return m_data.INT; }
  float get_float() const { return m_data.FLOAT; }
  char* get_string() const { return m_data.STRING; }
private:
  type m_type;
  union {
    int   INT;
    float FLOAT;
    char *STRING;
  } m_data;
};
template<typename ...Args>
std::string GetInsertString(const std::string& tableName, Args... args)
{
    std::string insertString = "INSERT INTO ";
    insertString += tableName;
    insertString += " VALUES(";
    std::vector<any> vec = {args...};
    std::ostringstream ss;
    for (unsigned i = 0; i < vec.size(); ++i)
    {
        switch(vec[i].get_type())
        {
            case any::Int:
                ss.str("");
                ss << vec[i].get_int();
                insertString += ss.str() + ",";
                break;
            case any::Float:
                ss.str("");
                ss << vec[i].get_float();
                insertString += ss.str() + ",";
                break;
            case any::String:
                ss.str("");
                insertString += "'" + std::string(vec[i].get_string()) + "'," ;
                break;
        }
    }
    insertString.pop_back();
    insertString += ");";
    return insertString;
}

其中 any 是基于此链接 How can I iterate over a packed variadic template argument list? 的类

但问题是我无法将 std::string 类型作为可变参数传递给此函数,因为我们在 any 类中有联合,因此需要你们的帮助才能将 std::string 类型传递为为插入查询构造值的参数

【问题讨论】:

    标签: c++ templates c++14 variadic-templates variadic


    【解决方案1】:

    您可以使用虚拟基类、模板包装器和智能指针,如下所示

    #include <string>
    #include <vector>
    #include <memory>
    #include <sstream>
    #include <iostream>
    
    
    struct anyBase
     { virtual int unusedVirt () { return 0; }; };
    
    template <typename T>
    struct anyW : public anyBase
     { 
       T val;
    
       anyW (T const & v0) : val{v0} { }
     };
    
    
    struct any
     {
       public: 
          enum type { Int, Float, String };
    
          any (int e)
             : m_type{Int}, m_data{new anyW<int>(e)} { }
    
          any (float e)
             : m_type{Float}, m_data{new anyW<float>(e)} { }
    
          any (char const * e)
             : m_type{String}, m_data{new anyW<std::string>(e)} { }
    
          any (std::string const & e)
             : m_type{String}, m_data{new anyW<std::string>(e)} { }
    
          any (any const & a) : m_type{a.m_type}, m_data{nullptr}
           {
             switch ( m_type )
              {
                case Int:
                   m_data.reset(new anyW<int>(a.get_int()));
                   break;
    
                case Float:
                   m_data.reset(new anyW<float>(a.get_float()));
                   break;
    
                case String:
                   m_data.reset(new anyW<std::string>(a.get_string()));
                   break;
              }
           }
    
          type get_type () const { return m_type; }
    
          int get_int () const
           { return dynamic_cast<anyW<int>*>(m_data.get())->val; }
    
          float get_float () const
           { return dynamic_cast<anyW<float>*>(m_data.get())->val; }
    
          std::string const & get_string () const
           { return dynamic_cast<anyW<std::string>*>(m_data.get())->val; }
    
       private:
          type m_type;
    
          std::unique_ptr<anyBase> m_data;
     };
    
    
    template<typename ...Args>
    std::string GetInsertString(const std::string& tableName, Args... args)
     {
       std::string insertString = "INSERT INTO ";
       insertString += tableName;
       insertString += " VALUES(";
       std::vector<any> vec = {args...};
       std::ostringstream ss;
       for (unsigned i = 0; i < vec.size(); ++i)
        {
          switch(vec[i].get_type())
           {
             case any::Int:
                ss.str("");
                ss << vec[i].get_int();
                insertString += ss.str() + ",";
                break;
             case any::Float:
                ss.str("");
                ss << vec[i].get_float();
                insertString += ss.str() + ",";
                break;
             case any::String:
                ss.str("");
                insertString += "'" + std::string(vec[i].get_string()) + "'," ;
                break;
           }
        }
       insertString.pop_back();
       insertString += ");";
       return insertString;
     }
    
    
    int main ()
     {
       std::cout << GetInsertString("fooTable", 1, 2.2f, "3", std::string("4"))
          << std:: endl;
       // print INSERT INTO fooTable VALUES(1,2.2,'3','4');
     }
    

    注意:

    • 这个解决方案也应该适用于 C++11

    • 我已经统一了char *std::string 的情况;我认为注册chat *

    • 是个坏主意
    • 使用std::unique_ptr,您需要copy_constructor,因为std::unique_ptr 中的复制构造函数已被删除,因此也删除了any 的默认复制构造函数

    • 更好的解决方案可能是等待传入(C++17,如果我没记错的话)std::variant

    【讨论】:

      【解决方案2】:
      typeof
      

      您可以使用typeof 并添加开关盒。例如,在新的 java 中,如果我没记错的话,您可以自动化一个半循环并同样看到某种循环。

      【讨论】:

      • 这是 c++,我说的是可变参数模板的参数包,我找不到任何最好的方法来逐一迭代
      • 参数类型没有迭代。奥立开关。您迭代这些值并为每个值进行切换。
      猜你喜欢
      • 2021-05-30
      • 1970-01-01
      • 2015-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多