Переведите коды возврата SQLITE_OK, ..., SQLITE_DONE в перечислимый класс в C ++ (без запроса клиентов включить заголовок C) - PullRequest
0 голосов
/ 05 апреля 2020

У меня есть класс persistence_manager_t, который скрывает доступные реализации для пользователей. Одна из реализаций заключается в использовании SQLite, чьи коды возврата C предварительная обработка определяет как

#define SQLITE_OK           0   /* Successful result */

Теперь я пытаюсь создать класс enum без записи вручную кода возврата, то есть

// persistence_manager_t.cpp
#include <sqlite3.h>
enum class persistence_manager_status {
    STATUS_OK = SQLITE_OK, STATUS_ROW = SQLITE_ROW, STATUS_DONE = SQLITE_DONE
};

но когда пользователи класса пытаются

auto rc = context->persistence->open(db_name);
if(rc != persistence_manager_status::STATUS_OK) {
    // TODO: gestione errori
}

, оказывается, что в заголовке должен быть определен класс enum, и поэтому я должен либо включить sqlite3.h в publi c header persistence_manager.h или пользователи класса должны сами включить sqlite3.h в свою реализацию (очень странно, поскольку им нужно установить sqlite-dev).

Согласно C ++ 17, существует ли такая вещь, как forward объявление или подобное для реализации класса enum также? Как мы можем использовать это?

1 Ответ

0 голосов
/ 05 апреля 2020

Вы можете переслать объявление enum class, но, похоже, вы хотите "объявить вперед" перечислителей этого enum. Это совсем другое дело, и это не то, что вы можете сделать. Предполагается, что перечислители являются константами времени компиляции, что означает, что значение этой константы должно быть видно при компиляции. Это означает, что имя перечислителя должно постоянно знать, что такое константа.

Однако вы можете объявить несколько глобальных константных переменных (extern const int name;) и определить их в любом исходном файле, который вам нравится. Однако вы теряете все преимущества счетчиков. Это не будут константные выражения (вне файла, в котором определены эти переменные), и, таким образом, компилятору придется выдавать код, который обращается к фактической памяти, чтобы извлечь значение переменной. Также не будет никакой связи между «перечислителями»; вы можете переключать их, но компилятор не будет знать, что значение должно быть одним из перечислителей.

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

Действительно, вы можете выбрать значения перечислителя, которые идентичны значениям SQLite, и использовать в своем коде static_asserts чтобы убедиться, что SQLite не изменит свои значения перечислителей за вашей спиной (к вашему сведению: они не собираются делать это в выпуске минорной версии; это нарушит совместимость ABI и, следовательно, каждого пользователя DLL / SO их библиотеки).

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