Опция 1: тип перечисления
По сути, у вас есть два разных режима чтения данных, которые вы различаете с помощью параметра bool type
. Это плохая форма по ряду причин, не в последнюю очередь из-за того, что неясно, что это за два типа или даже какой тип true
относится к false
.
Самый простой способ исправить это это ввести тип перечисления, который содержит именованное значение для всех возможных типов. Это было бы минимальным c изменением:
class DS
{
enum class mode
{
build, read
};
DS(const std::string &file_name, mode m);
};
Итак, мы могли бы использовать его как:
DS obj1("something.dat", DS::mode::build); // build from scratch
DS obj2("another.dat", DS::mode::read); // read pre-built
Это метод, который я бы использовал, поскольку он очень гибкий и расширяемый, если вы когда-нибудь захотите поддерживать другие режимы. Но реальная выгода - ясность на сайте вызова относительно того, что происходит. true
и false
часто неясны, когда используются в качестве аргументов функции.
Вариант 2: помеченные конструкторы
Еще одна опция для дифференциации этих функций, которая достаточно распространена для упоминание это понятие помеченных конструкторов. Это фактически означает добавление уникального типа для каждого режима, который вы хотите поддерживать, и использование его для перегрузки конструкторов.
class DS
{
static inline struct built_t {} build;
static inline struct read_t {} read;
DS(const std::string &file_name, build_t); // build from scratch
DS(const std::string &file_name, read_t); // read pre-built
};
Итак, мы могли бы использовать его как:
DS obj1("something.dat", DS::build); // build from scratch
DS obj2("another.dat", DS::read); // read pre-built
Как Вы можете видеть, что типы build_t
и read_t
введены для перегрузки конструктора. Действительно, когда используется этот метод, мы даже не называем параметр, потому что это просто средство разрешения перегрузки. Для обычного метода мы обычно просто отличаем имена функций, но мы не можем сделать это для конструкторов, поэтому этот метод существует.
Для удобства я добавил определение stati c экземпляров эти два типа тегов: build
и read
соответственно. Если бы они не были определены, мы должны были бы напечатать:
DS obj1("something.dat", DS::build_t{}); // build from scratch
DS obj2("another.dat", DS::read_t{}); // read pre-built
, что менее эстетично. Использование inline
- это функция C ++ 17, благодаря которой нам не нужно отдельно объявлять и определять переменные stati c. Если вы не используете C ++ 17, удалите inline
и определите переменные в вашем файле реализации как обычно для члена stati c.
Конечно, этот метод использует разрешение перегрузки и поэтому выполняется во время компиляции. Это делает его менее гибким, чем метод перечисления, поскольку он не может быть определен во время выполнения, что, возможно, потребуется для вашего проекта в дальнейшем.