如何基于构造函数参数填充常量成员数组

How to populate a const member array based on a constructor argument?

本文关键字:常量 成员 数组 填充 参数 何基于 构造函数      更新时间:2023-10-16

假设我有这个类:

template<int N>
class A {
    public:
    A(const char *s) ...
    private:
    const char buf[N];
};

模板就在那里,这样我就可以在没有动态内存分配的情况下配置阵列大小(这是一项要求)。buf成员是const,因为它旨在在对象初始化后在对象的生存期内保持不变。

为了澄清,我也没有访问STL的权限。

我有哪些选项可以定义此构造函数,以便将s的内容复制到buf中?一个选项是const_cast,但我正在寻找不需要它的替代方案。

@Richard Hodges提供的解决方案要求用char数组初始化类,而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 != ''? *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字节的缓冲区初始化。但是,如果您的情况确保了这一点,因此不需要进行此检查,您可以将其删除。代码也应该在没有它的情况下运行,不过我建议您至少将其保持在调试模式下。

注意,添加_assert作为成员会使类的大小至少增加一个字节。为了避免这种情况,我们可以使用空基类优化,并这样做:

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 != ''? *s++: *s)... }
        {}
    public:
        A(const char *s) : A(s, std::make_index_sequence<N>()) {}
    private:
       const char  buf[N];
};

这为我们每个实例节省了1个字节。

您使用索引序列和模板扩展。

#include <utility>
#include <cstdlib>

template<int N>
class A {
  template<size_t...Is>
    A(const char (&s)[N], std::index_sequence<Is...>)
    : buf{ s[Is]... }
  {}

    public:
    A(const char (&s)[N]) 
      : A(s, std::make_index_sequence<N>())
    {
    }
    private:
    const char buf[N];
};

int main()
{
  A<3> a("ab");
};

由于const-char[]是一种文字类型,它还允许类为constexpr:

#include <utility>
#include <cstdlib>

template<int N>
class A {
  template<size_t...Is>
    constexpr A(const char (&s)[N], std::index_sequence<Is...>)
    : buf{ s[Is]... }
  {}

    public:
    constexpr A(const char (&s)[N]) 
      : A(s, std::make_index_sequence<N>())
    {
    }
    private:
    const char buf[N];
};

int main()
{
  constexpr A<3> a("ab");
};

但这改变了签名。。。

好的,这个:

#include <utility>
#include <cstdlib>
#include <cstring>

template<int N>
class A {
  template<size_t...Is>
    constexpr A(const char *s, size_t len, std::index_sequence<Is...>)
    : buf{ (Is <= len ? s[Is] : char(0))... }
  {}

    public:
    constexpr A(const char *s) 
      : A(s, strlen(s), std::make_index_sequence<N>())
    {
    }
    private:
    const char buf[N];
};

int main()
{
  constexpr A<10> a("ab");
};