Я не понял зачем параметризовать параметрами открытия шаблон?
В моём понимании параметры открытия должны быть параметрами конструктора.
Иначе (пример грубый) — если у тебя функция принимает файл, то тебе прийдётся явно указывать в параметрах функции что этот файл должен быть FileOpening::OpenExisting.
D>Передавать параметры открытия конструктору, это привычка кодирования в стиле Си, объясните зачем передавать в конструктор или еще куда либо константы известные на этапе компиляции ?
Такое "модное" кодирование заставит все функции сделать шаблонными. Приведёт это к непомерной нагрузке на компилятор — более-менее сложный проект будет собираться часами.
D>Константы должны появится только один раз, в том месте где без них не обойтись, а проталкивать их по стеку не могу найти причину.
В случае шаблонного и не-шаблонного класса для вызова конструктора файла компилятор сгенерит одинаковый код (имею в виду вариант когда вызов конструктора будет инлайнится).
D>По отношению к файлу имеется ограниченный набор флагов для его открытия, читая Александреску раскладываем все варианты на стратегии и параметризуем ими шаблон. Указывая в параметрах функции что этот файл должен быть FileOpening::OpenExisting уже по объявлению легче определить что функция делает с файлом, она создает, удаляет или модифицирует существующий файл, весьма удобно.
Не стану оспаривать заслуги Александреску, но не стоит воспринимать всё им написанное как прямое руководство к действию. Книги его скорее дают представление о возможностях С++, чем являются практическим руководством. И уж тем более не стоит городить сложных решений там, где замечательно работают простые.
Здравствуйте, Left2, Вы писали:
L>Я не понял зачем параметризовать параметрами открытия шаблон? L>В моём понимании параметры открытия должны быть параметрами конструктора. L>Иначе (пример грубый) — если у тебя функция принимает файл, то тебе прийдётся явно указывать в параметрах функции что этот файл должен быть FileOpening::OpenExisting.
Передавать параметры открытия конструктору, это привычка кодирования в стиле Си, объясните зачем передавать в конструктор или еще куда либо константы известные на этапе компиляции ?
Константы должны появится только один раз, в том месте где без них не обойтись, а проталкивать их по стеку не могу найти причину.
По отношению к файлу имеется ограниченный набор флагов для его открытия, читая Александреску раскладываем все варианты на стратегии и параметризуем ими шаблон. Указывая в параметрах функции что этот файл должен быть FileOpening::OpenExisting уже по объявлению легче определить что функция делает с файлом, она создает, удаляет или модифицирует существующий файл, весьма удобно.
Здравствуйте, Left2, Вы писали:
L>Не стану оспаривать заслуги Александреску, но не стоит воспринимать всё им написанное как прямое руководство к действию. Книги его скорее дают представление о возможностях С++, чем являются практическим руководством. И уж тем более не стоит городить сложных решений там, где замечательно работают простые.
Мои 5копеек:
Упоминание Стратегий Александреску в контексте примера Demay не есть правильно, ибо в примере используются traits, а не policy, в моём понимании Policy Флександреску это паттерн GoF Strategy в примере, мы не наблюдаем ничего подобного и видим обычные traits. Для использования стратегий Александреску применяет наследование, что тоже согласуется с с GoF, от traits'ов, в свою очередь, обычно не наследуются, видимо потому, что traits'ы применяются для других целей, это характеристики, и какие-либо утилитарные функции косвенно связанные ( в отличии от прямой связи у Policy ) с поведением.
И кроме того, в примере Demay сам же и называет шаблонные параметры XXXTraits
ЗЫ
Возможно я ошибаюсь, я буду очень признателен если меня поправят
КЛ>Позволяет четко квалифицировать значения энума. КЛ>Кто-нибудь так делает?
Я так делаю. В нижеследующем коде рад выслушать критику. Идея была такая, чтобы параметром шаблона мог выступить ограниченный набор вариантов:
....
#if defined(WIN32)
#include <windows.h>
#define GENERIC_READ_WRITE (GENERIC_READ|GENERIC_WRITE)
#elif defined(_POSIX_)
#include <stdio.h> /* 'sprintf' */#include <unistd.h> /* 'lseek' */#include <fcntl.h> /* 'open' */#include <sys/stat.h> /* 'S_IRUSR,... */#include <sys/syslimits.h> /* 'PATH_MAX,... */#include <errno.h> /* 'extern int errno' */#include <string.h> /* "char* strerror( int errnum ); */#define CloseHandle(x) close(x)
#define MAX_PATH PATH_MAX
#define INVALID_HANDLE_VALUE (-1)
#define CREATE_NEW O_CREAT|O_EXCL
#define CREATE_ALWAYS O_CREAT|O_TRUNC
#define OPEN_EXISTING 0
#define OPEN_ALWAYS O_CREAT
#define TRUNCATE_EXISTING O_TRUNC
#define GENERIC_READ O_RDONLY
#define GENERIC_WRITE O_WRONLY
#define GENERIC_READ_WRITE O_RDWR
#define FILE_BEGIN SEEK_SET
#define FILE_CURRENT SEEK_CUR
#define FILE_END SEEK_END
#define FILE_FLAG_WRITE_THROUGH O_SYNC
typedef int HANDLE;
#else
#error ERROR: WIN32 or POSIX supported!
#endif
class FileOpening {
public:
enum Enum {
CreateNew=CREATE_NEW, //!< Creates a new file. The function fails if the specified file already exists.
CreateAlways=CREATE_ALWAYS, //!< Creates a new file. If the file exists, the function overwrites the file, clears the existing attributes, and combines the file attributes and flags specified by dwFlagsAndAttributes with FILE_ATTRIBUTE_ARCHIVE.
OpenExisting=OPEN_EXISTING, //!< Opens the file. The function fails if the file does not exist.
OpenAlways=OPEN_ALWAYS, //!< Opens the file, if it exists. If the file does not exist, the function creates the file as if dwCreationDisposition were CREATE_NEW.
TruncateExisting=TRUNCATE_EXISTING //!< Opens the file. Once opened, the file is truncated so that its size is zero bytes. The calling process must open the file with at least GENERIC_WRITE access. The function fails if the file does not exist.
};
};
class FileAccess {
public:
enum Enum {
ReadOnly=GENERIC_READ, //!< Open file for reading only.
ReadWrite=GENERIC_READ_WRITE, //!< Open file for reading and writing.
WriteOnly=GENERIC_WRITE //!< Open file for writing only.
};
};
................
template <
enum FileOpening::Enum OpenTraits,
enum FileAccess::Enum AccessTraits = FileAccess::ReadOnly,
enum FileShare::Enum ShareTraits = FileShare::NoShare
> class File {
public:
................
Здравствуйте, Left2, Вы писали:
L>Вот так вот навскидку — не вижу смысла параметризовать шаблон файла параметрами его открытия... L>Зачем такие сложности?
Тут нет сложностей, просто работать с файлами в виде:
File<FileOpening::OpenExisting> file("post.txt");
немного проще и приятнее, чем вызвая функции API. Тем более что, после того как файл создан/открыт параметры типа GENERIC_READ|GENERIC_WRITE или O_CREAT|O_EXCL все равно уже не изменить
Здравствуйте, megawatt, Вы писали:
M>Здравствуйте, Константин Л., Вы писали:
КЛ>>Здравствуйте, Centaur, Вы писали:
C>>>Здравствуйте, Константин Л., Вы писали:
КЛ>>>>