如何从 std::set 获取 constexpr 大小,并使用它返回一个 std::array ,其中包含 C++23 中 std::set 中的元素数量?

问题描述 投票:0回答:1

如何从

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 行中的错误得到解决,可能我会自己完成剩下的工作。

c++ constexpr c++23 constexpr-function c++26
1个回答
0
投票

不能在常量表达式中使用

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*
演员。

© www.soinside.com 2019 - 2024. All rights reserved.