为什么 std::vector::at 不能在使用范围的 for-each 循环中工作?

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

这是我尝试在 C++26(我知道,没有发布,但这是我给 gcc 的选项)和 GCC 14.2 中的编译时解析器实现的简化示例。

#include <iostream>
#include <ranges>
#include <string_view>
#include <vector>

using namespace std::string_view_literals;

template <class To>
inline constexpr auto static_caster = []<class From>(From &&from) -> To
    requires requires { static_cast<To>(std::declval<From>()); }
{ return static_cast<To>(std::forward<From>(from)); };

struct Test {
    bool value;
    constexpr Test(const std::string_view input) {
        const std::vector<std::string_view> lines =
            input | std::views::split('\n') |
            std::views::transform(static_caster<std::string_view>) |
            std::ranges::to<std::vector>();
        // const std::string_view line = lines.at(0);
        for (const std::string_view line : lines) {
            const std::vector<std::string_view> line_tokens =
                line | std::views::split(' ') |
                std::views::transform(static_caster<std::string_view>) |
                std::ranges::to<std::vector>();
            const std::string_view kind = line_tokens.at(0);
            this->value = "v" == kind;
        }
    }
};

int main(int argc, char *argv[]) {
    constexpr bool value = Test("v 1.0 2.0 3.0\n"sv).value;

    std::cout << value;

    return 0;
}

错误信息:

In file included from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/vector:68,
                 from <source>:4:
/opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/stl_vector.h: In function 'int main(int, char**)':
<source>:33:52:   in 'constexpr' expansion of 'Test(std::literals::string_view_literals::operator""sv(((const char*)"v 1.0 2.0 3.0\012"), 14))'
<source>:26:57:   in 'constexpr' expansion of 'line_tokens.std::vector<std::basic_string_view<char> >::at(0)'
/opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/stl_vector.h:1333:16:   in 'constexpr' expansion of '((const std::vector<std::basic_string_view<char> >*)this)->std::vector<std::basic_string_view<char> >::_M_range_check(__n)'
/opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/stl_vector.h:1292:35: error: call to non-'constexpr' function 'void std::__throw_out_of_range_fmt(const char*, ...)'
 1292 |           __throw_out_of_range_fmt(__N("vector::_M_range_check: __n "
      |           ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1293 |                                        "(which is %zu) >= this->size() "
      |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1294 |                                        "(which is %zu)"),
      |                                        ~~~~~~~~~~~~~~~~~~
 1295 |                                    __n, this->size());
      |                                    ~~~~~~~~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/new_allocator.h:35,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/x86_64-linux-gnu/bits/c++allocator.h:33,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/allocator.h:46,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/string:45,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/locale_classes.h:42,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/ios_base.h:43,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/ios:46,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/ostream:42,
                 from /opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/iostream:43,
                 from <source>:1:
/opt/compiler-explorer/gcc-trunk-20241219/include/c++/15.0.0/bits/functexcept.h:82:3: note: 'void std::__throw_out_of_range_fmt(const char*, ...)' declared here
   82 |   __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__,__cold__))
      |   ^~~~~~~~~~~~~~~~~~~~~~~~

这个示例不起作用,但是带有内部 for 循环的示例仅将其内容与索引 0 处的固定行一起使用。

有趣的是,当我从常量中删除

\n
时,它就起作用了。

问题是为什么以及如何解决这个问题?

c++ g++ constexpr generic-const-exprs
1个回答
0
投票

这个问题与花哨的 c++26 东西无关,它是一个简单(但很容易错过)的错误。如果您以

\n
结尾并在
\n
上拆分,您将得到一个空行。该空行将包含一个空标记。并且空字符串没有“第 0”元素。如果彼此之间有两个空格,也会出现该错误。

要解决此问题,您可以在转换为

std::views::filter([](auto&& x){return !x.empty();}) |
之前在两个循环中添加
vector
以过滤掉空字符串,因为它们不是标记。

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