Решение, предоставленное @Richard Hodges, требует, чтобы класс был инициализирован массивом символов, а не char const*
, который изменяет подпись конструктора. Если это не сработает для вашего случая, то здесь одно решение, которое делает не изменить подпись:
template<int N>
class A
{
template<size_t...Is>
A(const char * s, std::index_sequence<Is...>)
: _assert(std::strlen(s) <= N, "size of buffer is bigger than N"),
buf{ (Is, *s != '\0'? *s++: *s)... }
{}
public:
A(const char *s) : A(s, std::make_index_sequence<N>()) {}
private:
throwable _assert;
const char buf[N];
};
где throwable
определяется как:
struct throwable
{
throwable(bool b, char const * message){
if (not b)
throw std::invalid_argument(message);
}
};
Использование throwable
гарантирует, что buf
не инициализируется буфером, превышающим N
байтов. Если, однако, ваша ситуация гарантирует, что и, следовательно, эта проверка не нужна, вы можете ее удалить. Код должен работать и без него, хотя я бы предложил вам сохранить его как минимум в debug.
Обратите внимание, что добавление _assert
в качестве члена увеличивает размер класса как минимум на один байт. Чтобы избежать этого, мы могли бы использовать empty base class optimiation и сделать это вместо того, чтобы:
template<int N>
class A : private throwable
{
template<size_t...Is>
A(const char * s, std::index_sequence<Is...>)
: throwable(std::strlen(s) <= N, "size of buffer is bigger than N"),
buf{ (Is, *s != '\0'? *s++: *s)... }
{}
public:
A(const char *s) : A(s, std::make_index_sequence<N>()) {}
private:
const char buf[N];
};
Это экономит нам 1 байт для каждого экземпляра.
Можете ли вы изменить 'char buf [N]' на 'std :: array'? – Jarod42
@ Jarod42 Нет, к сожалению. У меня нет доступа к STL. – Ana
@ Вы можете скопировать источники libstdC++ или что-то еще? Даже если у вас нет доступа к 'std :: array', вы переделаете его прямо сейчас. Наверное, хуже, чем в оригинальной реализации. –