Используйте шаблоны Variadi c (или аналогичный механизм) для передачи списка типов в функцию - PullRequest
0 голосов
/ 18 апреля 2020

Я хотел бы реализовать оболочку класса для базы данных.
В настоящее время я работаю над функцией createTable.
Я пытался заставить ее работать так, чтобы пользователь определял типы
в качестве параметров шаблона и имен столбцов в качестве списка инициализатора, это шаблон функции:

template <typename ... Ts>
bool createTable(const std::string & tableName, const std::initializer_list<std::string> & columnNames);

И это тело метода:

template<typename ... Ts>
bool DatabaseConnection::createTable(const std::string &tableName, const std::initializer_list<std::string> & columnNames)
{
    constexpr size_t num_cols = sizeof...(Ts);

    assert(num_cols == columnNames.size());
    auto typetuple = std::tuple<Ts...>();

    std::vector<std::tuple<std::string, std::string>> columnNameAndType(num_cols);

    auto columnNameIterator = columnNames.begin();


    for(unsigned it = 0; it++ < columnNames.size(); it++){
        typedef std::tuple_element<it, typetuple>::type c; // non-type template argument is not a constant expression
        if(is_same<c, int> ...) //pseudocode
            std::string dbtype = "INTEGER"; //pseudocode

    }

}

К сожалению, строка tuple_element не работает, потому что она не является константным выражением. Теперь кто-то может спросить, почему я хочу назвать это так: createTable<int, std::string>("Users", {"ID", "Name"}); вместо того, чтобы просто пропустить два списка инициализаторов?

Ну, я просто хочу дистанцировать пользователя от интерфейса - если бы я мог определить тип it-h, я мог бы просто использовать что-то вроде decltype или is_same, чтобы определить тип, используемый в запросе на создание базы данных - пользователь просто говорит, какой тип он / она хочет, и класс Database определяет наилучший тип базы данных, соответствующий запросу пользователя.

Теперь это можно сделать с помощью списков инициализаторов, но это не будет временем компиляции, и Мне просто любопытно посмотреть, возможно ли это в полное время.

Я надеюсь, что моего объяснения проблемы достаточно.
Конечно, это в основном теоретическая проблема, но я думаю, что многие люди заинтересуются в таком синтаксисе, и я пока не нашел каких-либо решений по inte rnet.

1 Ответ

1 голос
/ 18 апреля 2020

Этот интерфейс, безусловно, возможен.

A for l oop не собирается этого делать, потому что один оператор / переменная / выражение / et c. не может иметь разные типы при разных оценках подкласса for. Вместо этого l oop должен быть через расширение пакета.

Для этого может помочь одна или несколько частных функций-помощников. Можно было бы получить все это в одном определении функции, используя обобщенную c лямбду, но немного неприятно.

// private static
template <typename T>
std::string DatabaseConnection::dbTypeName()
{
    if constexpr (std::is_same_v<T, int>)
        return "INTEGER";
    // ...
    else
        static_assert(!std::is_same_v<T,T>, "Unsupported type argument");
}

template<typename ... Ts>
bool DatabaseConnection::createTable(
    const std::string &tableName,
    std::initializer_list<std::string> columnNames)
{
    constexpr size_t num_cols = sizeof...(Ts);

    assert(num_cols == columnNames.size());

    std::vector<std::tuple<std::string, std::string>> columnNameAndType;

    auto columnNameIterator = columnNames.begin();

    (columnNameAndType.emplace_back(*columnNameIterator++, dbTypeName<Ts>()), ...);

    // ...    
}
...