Отображение привязок ODB C к обратному вызову функции через порядок вычисления аргументов функции - PullRequest
0 голосов
/ 15 апреля 2020

Я пытаюсь упростить кодовую базу C / C ++, которая вызывает SQL операторы БД сервера и / или хранимые процедуры из SQL сервера путем написания шаблонов variadi c различного рода. Я успешно написал функцию doQuery, которая принимает дополнительные параметры, которые автоматически связываются с запросом по типу, например, логическое, двойное, строковое, в качестве аргументов ввода или ввода / вывода.

Текущая проблема:

Для запросов, которые возвращают наборы результатов, я изо всех сил пытаюсь произвести оптимальные простые вызовы шаблонов.

Я пробовал кортежи, но они непопулярны среди традиционной команды разработчиков C, и мне не нравится они сами.

Так что я принимаю функцию, которая вызывается обратно с данными каждой строки, которую пользователь может выбрать для вставки / init {} в любой форме, например, pu sh в захваченный вектор структур , Исходя из сигнатуры обратного вызова, я генерирую привязки SQLBindCol для ODB C степени сложности n в массиве информации привязки для возвращаемых столбцов.

например,

std::vector<MyStruct> result;

auto functor = [&result](int id, string name, bool isOK, string address) {
  result.push_back(MyStruct{id,name,isOK,address});
}

c.doQuery(functor, "select id, name, isOK, address from MyTable;" /**/);

( /**/ показывает, где можно указать параметры для заполнения '?', Что у меня прекрасно работает, но в этом простом примере его нет).

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

template <typename T...>
InternalFunction(T)

[...]

vector<Binding> columns;

[...]

int i = 0;
functor(GetResult<T>(columns, i++)...);

GetResult возвращает столбец из i-го элемента вектора привязки в виде нужный тип в вызове функции. Но C ++ не гарантирует порядок оценки аргументов. Итак, согласно { ссылка } в потоке Как гарантировать порядок вычисления аргументов при вызове объекта функции? , решение довольно простое:

struct OrderedCall
{
    template <typename F, typename ...Args>
    OrderedCall(F && f, Args &&... args)
    {
        std::forward<F>(f)(std::forward<Args>(args)...);
    }
};

[...]

OrderedCall{functor, GetResult<T>(columns, i++)...};

К сожалению, Visual Studio 15 (MSV C) явно не работает и все еще переупорядочивает оценки, например, если есть строковый аргумент, который вычисляется последним, что приводит к результатам происходят из произвольно выбранных членов вектора-столбца, а не выбирают их по порядку, так как они были автоматически связаны с использованием методов variadi c.

Я не знаю другого способа связать аргументы с последовательными векторные записи для решения этой проблемы и обеспечения надежной работы обратного вызова функтора.

Если я отключу оптимизацию и встраивание функций и уберу трюк со структурой OrderedCall, оценки будут происходить довольно надежно в обратном порядке, который можно использовать, но это не так. хорошее решение, потому что оно ни практично, ни надежно.

Я не могу намек на другой способ вызова функции во время: повторного связывания аргументов со столбцами, сохранения типов аргументов и т. д. c.

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

Так что мои вопросы:

  • Есть ли способ вызвать мою функцию std :: function с помощью set аргументов, генерируемых шаблонной функцией из вектора? Я посмотрел на std :: bind, но, похоже, он не предлагал простой способ решения проблемы, но, возможно, итеративное связывание одного аргумента за раз, вывод одной функции из другой из другой ...

  • Должен ли я создать рекурсивный шаблон только для вызова функтора? (это была бы уродливая реализация, в лучшем случае передававшая аргументы через многоуровневую сложность, если она вообще работала).

  • Я пропустил более простое / лучшее решение для упрощения его до pu sh привести строки в вектор структур?

  • Я заново изобретаю колесо? Это упрощение связывания variadi c уже доступно для sql -server / odb c / msv c?

  • Не нарушена ли более поздняя версия Visual Studio, как эта ?

Я сам ответил на поломку VS следующим тестом:

#include <iostream>
#include <string>

struct OrderedCall
{
        template <typename F, typename ...Args>
        OrderedCall(F && f, Args &&... args)
        {
                std::forward<F>(f)(std::forward<Args>(args)...);
        }
};
void foo(int, std::string s, char, bool) {
        int i = 0;
        i++;
}

int bar() {
        return 10;
}

template <typename T>
T echo(T x) {
        std::cout << " " << x;
        return x;
}

int main(int argc, char**argv) {
        std::string goo = "Goo";

        std::cout << "Occurance: " << bar() << " " << goo << " " << 'x' << " " << false;

        std::cout << std::endl << "Unordered call:";
        foo(echo(bar()), echo(goo), echo('x'), echo(false));

        std::cout << std::endl << "Ordered call:";
        OrderedCall{ foo, echo(bar()), echo(goo), echo('x'), echo(false) };

        std::cout << std::endl << "Try in Debug and Release modes. " << std::endl
                << "Ordered should match Occurance" << std::endl;
}

Видимо все еще не работает в последнем обновлении Visual Studio 19, в режиме отладки следующее:

Occurance: 10 Goo x 0
Unordered call: Goo 0 x 10
Ordered call: 0 x 10 Goo
Try in Debug and Release modes.
Ordered should match Occurance

См .: https://timsong-cpp.github.io/cppwp/n3337/dcl.init.list и https://timsong-cpp.github.io/cppwp/n3337/class.expl.init

В пределах списка инициализатора списка фигурных скобок предложения инициализатора, включая любые, которые являются результатом расширений пакета ([temp.variadic]), оцениваются в порядке, в котором они появляются. То есть каждое вычисление значения и побочный эффект, связанный с данным предложением инициализатора, упорядочивается перед каждым вычислением значения и побочным эффектом, связанным с любым предложением инициализатора, которое следует за ним в списке через запятую списка инициализатора. [Примечание: этот порядок оценки выполняется независимо от семантики инициализации; например, он применяется, когда элементы списка инициализатора интерпретируются как аргументы вызова конструктора, хотя обычно нет никаких ограничений последовательности аргументов вызова. - конец заметки]

[Вышеупомянутая заметка в тексте, не добавлена ​​мной.]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...