如何基于构造函数参数填充常量成员数组
How to populate a const member array based on a constructor argument?
假设我有这个类:
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");
};
相关文章:
- 私有类型的静态常量成员
- constexpr构造函数需要常量成员函数时出现问题
- Clang 格式 10.0 与 5.0 常量成员函数的格式不同
- 为什么"具有常量成员的结构"类型的指针不能指向"具有非常量成员的结构"?
- 常量成员函数中成员变量的类型
- 如何处理运算符=中的常量成员?
- 常量成员和没有setter的私有成员之间有什么区别
- C++:允许临时对象调用非常量成员函数的设计理念是什么?
- 移动具有常量成员的类的构造和分配
- ARM C++编译器不会编译具有可变常量成员的结构
- 强制在编译时计算类的类的常量成员
- 类中常量成员函数的 c++ 链接错误
- 为什么常量成员可以初始化两次?
- 专用常量成员函数的成员检测
- 与其他静态const成员初始化静态常量成员
- 具有静态和常量成员变量的对象
- 结构中的常量成员即使在初始化后也返回 0
- 在非常量成员函数中,为什么点这个非常量,而 decltype 指针这是常量
- 有没有一种通用方法来"unprotect"静态常量成员?
- 如何初始化共享复杂初始化代码的多个常量成员变量?