Создание универсальной функции вставки

Я пытался создать общую функцию, которая может принимать имя и значения таблицы и возвращать вставку в запрос, и придумал что-то вроде ниже:

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

где любой класс основан на этой ссылке Как Я перебираю упакованный список аргументов шаблона с переменным числом аргументов?

Но проблема в том, что я не могу передать тип std::string в качестве вариационного аргумента этой функции, так как у нас есть объединение в любом классе, поэтому нужна помощь от вас, ребята, чтобы передать тип std::string в качестве аргумента для построения значений для запроса на вставку.


person PapaDiHatti    schedule 11.03.2017    source источник


Ответы (2)


Вы можете использовать виртуальный базовый класс, оболочку шаблона и интеллектуальные указатели, пишущие что-то следующим образом.

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

Обратите внимание, что:

  • это решение должно работать и с С++ 11

  • Я объединил случаи char * и std::string; Я думаю, что это плохая идея зарегистрировать chat *

  • используя std::unique_ptr, вам нужен copy_constructor, потому что конструктор копирования в std::unique_ptr удаляется, поэтому также удаляется конструктор копирования по умолчанию для любого

  • лучшим решением может быть ожидание входящего (С++ 17, если я не ошибаюсь) std::variant

person max66    schedule 11.03.2017

typeof

Вы можете использовать use typeof и добавить случаи переключения. В новой java, например, вы можете автоматизировать полуцикл и увидеть, что это тоже своего рода цикл, если я не ошибаюсь.

person Vitali Pom    schedule 11.03.2017
comment
это С++, и я говорю о пакете параметров вариативного шаблона, и я не смог найти лучший способ перебора этого по одному - person PapaDiHatti; 11.03.2017
comment
Нет итерации по типу параметров. Омский переключатель. Вы перебираете значения и для каждого выполняете переключение. - person Vitali Pom; 11.03.2017