C++ 如何将复杂数据结构序列化为C+中的编码constexpr初始化+;20
目标是将大型数据结构序列化为C++ 如何将复杂数据结构序列化为C+中的编码constexpr初始化+;20,c++,constexpr,c++20,consteval,C++,Constexpr,C++20,Consteval,目标是将大型数据结构序列化为constexpr初始化,因此它们将成为.text或.rodata段的一部分,并可用于consteval,constexpr等 数据结构包含用于交叉引用/索引等的容器。所有这些代码都将生成,因此我们可以使用相同或等效的容器逻辑计算代码生成器中的容器状态,然后按原样序列化容器状态 C++不支持constexpr的非瞬态动态分配 “在Kona 2019年,这种方法被认为过于脆弱,因此从功能集中删除了非暂时性分配。” 因此,不可能使用std::或自制的动态容器 使用(可变的
constexpr
初始化,因此它们将成为.text
或.rodata
段的一部分,并可用于consteval
,constexpr
等
数据结构包含用于交叉引用/索引等的容器。所有这些代码都将生成,因此我们可以使用相同或等效的容器逻辑计算代码生成器中的容器状态,然后按原样序列化容器状态
C++不支持constexpr
的非瞬态动态分配
“在Kona 2019年,这种方法被认为过于脆弱,因此从功能集中删除了非暂时性分配。”
因此,不可能使用std::
或自制的动态容器
使用(可变的?)模板似乎也是不可能的,因为数据结构必须以运行时动态的方式可用,即任何模板的使用都需要在顶部设置一个类型擦除层,这看起来很不方便。看
如本文所述,下一次尝试是尝试序列化为复合文本。看
标准C++ 20实际上并不支持复合文本,但我们可以依赖编译器扩展来支持C++中的这个C特性。似乎在所有主要的C++编译器中都可用。 下面的例子只是一个很小的概念证明(或尝试)
问题:以下内容适用于Clang,但不适用于GCC为什么?有别的办法吗?#include <memory>
template <typename K, typename V>
struct Entry{
K key;
V value;
};
template <typename K, typename V>
struct Bucket{
size_t n;
// C++ cannot initialize a flexible array in a struct, use a pointer.
Entry<K, V> *entries;
};
template <typename K, typename V>
struct HashMap{
using bucket_t = Bucket<K, V>;
using entry_t = Entry<K, V>;
size_t n;
// C++ cannot initialize a flexible array in a struct, use a pointer.
bucket_t *buckets;
constexpr V get(K key) const {
const size_t i = key % n;
const auto &bucket = buckets[i];
for (size_t j = 0; j < bucket.n; ++j) {
if (bucket.entries[j].key == key) {
return bucket.entries[j].value;
}
}
return {};
}
};
using MyHashMap = HashMap<int, double>;
constexpr MyHashMap map =
{
2,
// Because we can't initialize a flexible array, we need to employ a so-called
// compound literal and let it decay to a pointer.
(MyHashMap::bucket_t[])
{
{
3,
(MyHashMap::entry_t[]) // dito
{ {0, 1.2}, {2, 2.4}, {6, 3.6} }
},
{
4,
(MyHashMap::entry_t[]) // dito
{ {1, 0.0}, {5, 2.0}, {11, 4.0}, {13, 1.0} }
}
}
};
// Serves as proof of concept by succeeding as consteval.
consteval int proofOfConcept() {
// Should return 76 as a constant,
return 10*(map.get(0) + map.get(11) + map.get(2));
}
int main() {
return proofOfConcept();
}
#包括
模板
结构条目{
K键;
V值;
};
模板
结构桶{
尺寸;
//C++无法初始化结构中的灵活数组,使用指针。
条目*条目;
};
模板
结构哈希映射{
使用铲斗\u t=铲斗;
使用entry\u t=entry;
尺寸;
//C++无法初始化结构中的灵活数组,使用指针。
桶_t*桶;
constexpr V get(K键)const{
常量大小\u t i=键%n;
const auto&bucket=bucket[i];
对于(尺寸j=0;j
在GCC上,这是失败的
<source>: In function 'int main()':
<source>:94:26: in 'constexpr' expansion of 'proofOfConcept()'
<source>:90:23: in 'constexpr' expansion of 'map.HashMap<int, double>::get(0)'
<source>:94:26: error: the value of '._anon_115' is not usable in a constant expression
94 | return proofOfConcept();
| ~~~~~~~~~~~~~~^~
<source>:84:9: note: '._anon_115' was not declared 'constexpr'
84 | }
| ^
:在函数“int main()”中:
:94:26:在“constexpr”中扩展了“proofconcept()”
:90:23:在“map.HashMap::get(0)”的“constexpr”扩展中
:94:26:错误:“.\n\u 115”的值在常量表达式中不可用
94 |返回概念证明();
| ~~~~~~~~~~~~~~^~
:84:9:注意:“.\u anon_115”未声明为“constexpr”
84 | }
| ^
请在此浏览:
作为康桓瑋 他指出,这是一个终生的问题。似乎每个嵌套数组文字都需要单独定义为一个符号,然后在其位置使用。这也避免了非标准的复合文字用法 但它增加了传递常数的问题。我们需要能够用常量参数化包含结构 因此,这似乎是一个解决方案:
#include <memory>
template<bool isConst, typename T>
struct TransitiveConst { using Result = T; };
template<typename T>
struct TransitiveConst<true, T> { using Result = const T; };
template <typename K, typename V>
struct Entry{
K key;
V value;
};
template <typename E>
struct Bucket{
size_t n;
// C++ cannot initialize a flexible array in a struct, use a pointer.
E *entries;
};
template <bool isConst, typename K, typename V>
struct HashMap{
using entry_t = typename TransitiveConst<isConst, Entry<K, V>>::Result;
using bucket_t = typename TransitiveConst<isConst, Bucket<entry_t>>::Result;
size_t n;
// C++ cannot initialize a flexible array in a struct, use a pointer.
bucket_t *buckets;
constexpr V get(K key) const {
const size_t i = key % n;
const auto &bucket = buckets[i];
for (size_t j = 0; j < bucket.n; ++j) {
if (bucket.entries[j].key == key) {
return bucket.entries[j].value;
}
}
return {};
}
};
using MyHashMap = HashMap<true, const int, const double>;
constexpr MyHashMap::entry_t entry0[] = { {0, 1.2}, {2, 2.4}, {6, 3.6} };
constexpr MyHashMap::entry_t entry1[] = { {1, 0.0}, {5, 2.0}, {11, 4.0}, {13, 1.0} };
constexpr MyHashMap::bucket_t buckets[] = {
{
std::size(entry0),
entry0
},
{
std::size(entry1),
entry1
}
};
constexpr MyHashMap map =
{
std::size(buckets),
buckets
};
// Serves as proof of concept by succeeding as consteval.
consteval int proofOfConcept() {
// Should return 76 as a constant,
return (10*(map.get(0) + map.get(11) + map.get(2)));
}
int main() {
return proofOfConcept();
}
#包括
模板
结构transitionconst{using Result=T;};
模板
结构transitionconst{using Result=const T;};
模板
结构条目{
K键;
V值;
};
模板
结构桶{
尺寸;
//C++无法初始化结构中的灵活数组,使用指针。
E*条目;
};
模板
结构哈希映射{
使用entry\u t=typename transitionconst::Result;
使用bucket\u t=typename transitionconst::Result;
尺寸;
//C++无法初始化结构中的灵活数组,使用指针。
桶_t*桶;
constexpr V get(K键)const{
常量大小\u t i=键%n;
const auto&bucket=bucket[i];
对于(尺寸j=0;j
原因是gcc认为您在
get
函数中访问bucket
的内容是非法的,不能在编译时执行。这似乎是关于复合文字的生存期的问题。您的问题可以归结为:。“在C中,复合文字指定具有静态或自动存储持续时间的未命名对象。在