如何从
constexpr
获得 size
std::set
,我可以用它来返回 std::array
,其中包含 C++23 或未来 C++ 中 std::set
中的元素数量26,只要受到 G++
或 Clang
? 的支持
用例是一个
constexpr
解析器,它返回一个“复杂”对象,其中包含数量灵活的各种元素。
我看到了 我可以制作 std::set 的 constexpr 对象吗?,这似乎是在类似的方向上,但我在返回值中已经用
std::set
替换了 frozen::set
。
然而,不知何故我必须确定它的大小参数。
frozen
顺便说一句来自https://github.com/serge-sans-paille/frozen.
因为
std::set
没有 constexpr
size
方法,我尝试在中间放一个 std::vector
,这显然没有帮助。
我有一些简化的代码:
#include <algorithm>
#include <array>
#include <set>
#include <string_view>
#include <vector>
#include <frozen/set.h>
#include <frozen/bits/basic_types.h>
using namespace std::string_view_literals;
constexpr auto test(const std::string_view input) {
std::set<std::string_view> my_set;
my_set.emplace(input); // For sure the reality is more complicated and can lead to a flexible number of elements
constexpr std::vector<std::string_view> my_vec(my_set.begin(), my_set.end());
constexpr std::array<std::string_view, my_vec.size()> my_arr{};
std::copy_n(my_vec.begin(), my_vec.size(), my_arr.begin());
constexpr frozen::bits::carray<std::string_view, my_vec.size()> my_carr(my_arr);
return frozen::set<std::string_view, my_vec.size()>(my_carr);
}
int main() {
constexpr auto frozen_set = test("test"sv);
return 0;
}
即使我使用 G++ 的开发版本(14.0.1),我也会收到以下错误:
test.cpp: In function ‘constexpr auto test(std::string_view)’:
test.cpp:14:68: error: temporary of non-literal type ‘std::set<std::basic_string_view<char> >::iterator’ {aka ‘std::_Rb_tree<std::basic_string_view<char>, std::basic_string_view<char>, std::_Identity<std::basic_string_view<char> >, std::less<std::basic_string_view<char> >, std::allocator<std::basic_string_view<char> > >::const_iterator’} in a constant expression
14 | constexpr std::vector<std::string_view> my_vec(my_set.begin(), my_set.end());
| ~~~~~~~~~~~~^~
In file included from /usr/include/c++/14/set:62,
from test.cpp:3:
/usr/include/c++/14/bits/stl_tree.h:324:12: note: ‘std::_Rb_tree_const_iterator<std::basic_string_view<char> >’ is not literal because:
324 | struct _Rb_tree_const_iterator
| ^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_tree.h:324:12: note: ‘std::_Rb_tree_const_iterator<std::basic_string_view<char> >’ is not an aggregate, does not have a trivial default constructor, and has no ‘constexpr’ constructor that is not a copy or move constructor
test.cpp:16:59: error: request for member ‘begin’ in ‘my_arr’, which is of non-class type ‘const int’
16 | std::copy_n(my_vec.begin(), my_vec.size(), my_arr.begin());
| ^~~~~
如果第 14 行中的错误得到解决,可能我会自己完成剩下的工作。
不能在常量表达式中使用
std::set
,因为它的成员函数都没有标记为 constexpr
。
作为解决方法,您可以创建一个
std::vector
并通过排序和删除重复元素来“设置”它:
template <typename T>
void setify(std::vector<T>& v) {
std::ranges::sort(v);
// Eliminate non-unique elements, which generates some garbage towards the end.
auto one_past_unique_elements = std::ranges::unique(v).begin();
// Reduce the size of the vector to get rid of the garbage.
v.erase(one_past_unique_elements, v.end());
}
注意:据我所知,没有任何针对 C++26 的提案可以向关联容器添加
constexpr
功能。我确信这存在一些实现困难,例如某些标准库直接在容器中保留“结束节点”。也许在P2738R1之后有可能:constexpr
从void*
演员。