将 constexpr 数组复制到 class
Copy constexpr array into class
假设我有一个 class:
class MyClass{
char array[12];
public:
MyClass(const char* arr) {
for (int x = 0; x < 12; x++){
array[x] = arr[x];
}
}
};
是否可以使 MyClass
构造函数 constexpr
。棘手的部分是初始化新数组....
您可以使用 std::array
代替 C 数组和 everything just works:
#include <array>
class MyClass{
std::array<char, 12> array;
public:
constexpr MyClass(std::array<char, 12> arr) : array(arr){
}
};
int main() {
MyClass m({'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'});
}
我不知道如何使用 "Hello World!"
而不是那个字符列表来初始化数组。
我想(我希望)以下示例可以提供帮助。
我将您的 MyClass
转换为模板化 class,其中模板参数是数组的维度 (12);我希望这不是问题。
应该适用于 C++11 和 C++14
#include <iostream>
template <std::size_t ...>
struct range
{ };
template <std::size_t N, std::size_t ... Next>
struct rangeH
{ using type = typename rangeH<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct rangeH<0U, Next ... >
{ using type = range<Next ... >; };
template <std::size_t Dim>
class MyClass
{
public:
char array[Dim];
template <std::size_t ... rng>
constexpr MyClass (const char arr[Dim], const range<rng...> &)
: array{ arr[rng]... }
{ }
constexpr MyClass (const char arr[Dim])
: MyClass(arr, typename rangeH<Dim>::type())
{ }
};
int main ()
{
constexpr MyClass<12> mc1("0123456789a");
constexpr MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");
std::cout << mc1.array << std::endl;
std::cout << mc2.array << std::endl;
return 0;
}
p.s.: 对不起我的英语不好
--- 编辑:添加了 C++14 示例 --
如果你(当你)可以使用 C++14,你可以使用 std::index_sequence
和 std::make_index_sequence
,避免 range
和 rangeH
。
例子变成
#include <utility>
#include <iostream>
template <std::size_t Dim>
class MyClass
{
public:
char array[Dim];
template <std::size_t ... rng>
constexpr MyClass (const char arr[Dim],
const std::index_sequence<rng...> &)
: array{ arr[rng]... }
{ }
constexpr MyClass (const char arr[Dim])
: MyClass(arr, std::make_index_sequence<Dim>())
{ }
};
int main ()
{
MyClass<12> mc1("0123456789a");
MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");
std::cout << mc1.array << std::endl;
std::cout << mc2.array << std::endl;
return 0;
}
-- 附录:如何避免显式维度指示--
如果您觉得计算常量字符串中的字符很烦人,auto
是您的朋友;如果您以这种方式声明一个 constexpr
函数
template <std::size_t Dim>
constexpr MyClass<Dim> makeMyClass (const char (&arr)[Dim])
{ return MyClass<Dim> { arr }; }
你可以用这种方式声明MyClass<N>
类型的变量(或常量)
constexpr auto mc1 = makeMyClass("0123456789a");
constexpr auto mc2 = makeMyClass("0123456789abcdefghijklmnopqrstuvwxyz");
改为
constexpr MyClass<12> mc1("0123456789a");
constexpr MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");
也适用于 C++14 和 C++11。
这是一个不需要您在使用 class 之前指定大小的解决方案。
请注意,这是一个 C++14 解决方案。
无论如何,您可以轻松找到整数序列内容的 C++11 实现并将解决方案调整为 C++11。
代码如下:
#include<functional>
class MyClass{
const char arr[12];
const std::size_t sz;
template<std::size_t... I>
constexpr
MyClass(std::integer_sequence<std::size_t, I...>, const char *str)
: arr{str[I]...}, sz{sizeof...(I)}
{ }
public:
template<int N>
constexpr
MyClass(const char (&str)[N])
: MyClass(std::make_index_sequence<N>(), str)
{ static_assert(N < 12, "!"); }
constexpr std::size_t size() const { return sz; }
constexpr char operator[](int n) const { return arr[n]; }
};
int main() {
constexpr MyClass c{"foo"};
static_assert(c.size() == 4, "!");
static_assert(c[0] == 'f', "!");
static_assert(c[1] == 'o', "!");
static_assert(c[2] == 'o', "!");
static_assert(c[3] == '[=10=]', "!");
}
模板欺骗,如评论中所述,但它有效。
如果您可以访问 c++14 编译器,则可以简单地使用 for 循环。但是,必须初始化内存。一个缺点是数组被写入了两次,但这可能是在编译时完成的。一个好处就是代码简单很多。
struct array_wrapper{
char array[11]{};
constexpr array_wrapper(const char (& other)[11]) {
for (unsigned j=0;j<sizeof(other)-1;j++){
other[j]+=text[j];
}
}
};
假设我有一个 class:
class MyClass{
char array[12];
public:
MyClass(const char* arr) {
for (int x = 0; x < 12; x++){
array[x] = arr[x];
}
}
};
是否可以使 MyClass
构造函数 constexpr
。棘手的部分是初始化新数组....
您可以使用 std::array
代替 C 数组和 everything just works:
#include <array>
class MyClass{
std::array<char, 12> array;
public:
constexpr MyClass(std::array<char, 12> arr) : array(arr){
}
};
int main() {
MyClass m({'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'});
}
我不知道如何使用 "Hello World!"
而不是那个字符列表来初始化数组。
我想(我希望)以下示例可以提供帮助。
我将您的 MyClass
转换为模板化 class,其中模板参数是数组的维度 (12);我希望这不是问题。
应该适用于 C++11 和 C++14
#include <iostream>
template <std::size_t ...>
struct range
{ };
template <std::size_t N, std::size_t ... Next>
struct rangeH
{ using type = typename rangeH<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct rangeH<0U, Next ... >
{ using type = range<Next ... >; };
template <std::size_t Dim>
class MyClass
{
public:
char array[Dim];
template <std::size_t ... rng>
constexpr MyClass (const char arr[Dim], const range<rng...> &)
: array{ arr[rng]... }
{ }
constexpr MyClass (const char arr[Dim])
: MyClass(arr, typename rangeH<Dim>::type())
{ }
};
int main ()
{
constexpr MyClass<12> mc1("0123456789a");
constexpr MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");
std::cout << mc1.array << std::endl;
std::cout << mc2.array << std::endl;
return 0;
}
p.s.: 对不起我的英语不好
--- 编辑:添加了 C++14 示例 --
如果你(当你)可以使用 C++14,你可以使用 std::index_sequence
和 std::make_index_sequence
,避免 range
和 rangeH
。
例子变成
#include <utility>
#include <iostream>
template <std::size_t Dim>
class MyClass
{
public:
char array[Dim];
template <std::size_t ... rng>
constexpr MyClass (const char arr[Dim],
const std::index_sequence<rng...> &)
: array{ arr[rng]... }
{ }
constexpr MyClass (const char arr[Dim])
: MyClass(arr, std::make_index_sequence<Dim>())
{ }
};
int main ()
{
MyClass<12> mc1("0123456789a");
MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");
std::cout << mc1.array << std::endl;
std::cout << mc2.array << std::endl;
return 0;
}
-- 附录:如何避免显式维度指示--
如果您觉得计算常量字符串中的字符很烦人,auto
是您的朋友;如果您以这种方式声明一个 constexpr
函数
template <std::size_t Dim>
constexpr MyClass<Dim> makeMyClass (const char (&arr)[Dim])
{ return MyClass<Dim> { arr }; }
你可以用这种方式声明MyClass<N>
类型的变量(或常量)
constexpr auto mc1 = makeMyClass("0123456789a");
constexpr auto mc2 = makeMyClass("0123456789abcdefghijklmnopqrstuvwxyz");
改为
constexpr MyClass<12> mc1("0123456789a");
constexpr MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");
也适用于 C++14 和 C++11。
这是一个不需要您在使用 class 之前指定大小的解决方案。
请注意,这是一个 C++14 解决方案。
无论如何,您可以轻松找到整数序列内容的 C++11 实现并将解决方案调整为 C++11。
代码如下:
#include<functional>
class MyClass{
const char arr[12];
const std::size_t sz;
template<std::size_t... I>
constexpr
MyClass(std::integer_sequence<std::size_t, I...>, const char *str)
: arr{str[I]...}, sz{sizeof...(I)}
{ }
public:
template<int N>
constexpr
MyClass(const char (&str)[N])
: MyClass(std::make_index_sequence<N>(), str)
{ static_assert(N < 12, "!"); }
constexpr std::size_t size() const { return sz; }
constexpr char operator[](int n) const { return arr[n]; }
};
int main() {
constexpr MyClass c{"foo"};
static_assert(c.size() == 4, "!");
static_assert(c[0] == 'f', "!");
static_assert(c[1] == 'o', "!");
static_assert(c[2] == 'o', "!");
static_assert(c[3] == '[=10=]', "!");
}
模板欺骗,如评论中所述,但它有效。
如果您可以访问 c++14 编译器,则可以简单地使用 for 循环。但是,必须初始化内存。一个缺点是数组被写入了两次,但这可能是在编译时完成的。一个好处就是代码简单很多。
struct array_wrapper{
char array[11]{};
constexpr array_wrapper(const char (& other)[11]) {
for (unsigned j=0;j<sizeof(other)-1;j++){
other[j]+=text[j];
}
}
};