The solution provided by @Richard Hodges requires the class be initialized with char array, as opposed to char const*
, which changes the signature of the constructor. If that doesn't work for your case, then here is one solution which does not change the signature:
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];
};
where throwable
is defined as:
struct throwable
{
throwable(bool b, char const * message){
if (not b)
throw std::invalid_argument(message);
}
};
The use of throwable
ensures that buf
doesn't get initialized with buffer larger than N
bytes. If however your situation ensures that and thus doesn't need this check, you could remove it. The code should work without it as well, though I'd suggest you to keep it at least in debug mode.
Note that the addition of _assert
as member increases the size of the class at least by one byte. To avoid this, we could use empty base class optimiation and do this instead:
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];
};
That saves us 1 byte per instance.