constexpr 组合评估失败

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

我尝试使用

constexpr
并尝试将 ipv4 地址解析为四位数字,但它不起作用。所以我将代码精简到失败的程度:

#include <cstdint>
#include <stdexcept>
#include <string_view>

#define WORKS 1

static constexpr uint8_t
getIpVal(const std::string_view &sv) noexcept {

    size_t pos = 0;
    auto len = sv.size();
    unsigned long val = 0;

    while (sv[pos] >= '0' && sv[pos] <= '9' && pos < len) {
        int digit = sv[pos] - '0';
        val *= 10;
        val += digit;
        if (val > UINT8_MAX) {
            return 0;
            // throw std::invalid_argument(sv.data());
        }
        ++pos;
    }

    if (pos < len) {
            return 0;
        // throw std::invalid_argument(sv.data());
    }

    return val;
}

static constexpr auto
operator""_ipv4(const char *ipv4Ptr, const size_t size) {
    const std::string_view ipv4Str(ipv4Ptr, size);

    const auto pos1 = ipv4Str.find('.');
    if (pos1 == std::string_view::npos) {
        throw std::invalid_argument(ipv4Ptr);
    }
    
    const auto str1 = ipv4Str.substr(0, pos1);

#if WORKS
    return str1;
#else
    return getIpVal(str1);
#endif
}

auto
test1() {
    return "127.0.0.1"_ipv4;
}

auto
test2() {
    return getIpVal("127");
}

我正在尝试使用编译器资源管理器来编译它:https://godbolt.org/z/aY3ETo6ba

只要将

WORKS
定义为
1
,一切似乎都工作正常:

.LC0:
        .string "127.0.0.1"
test1():
        mov     eax, 3
        mov     edx, OFFSET FLAT:.LC0
        ret
test2():
        mov     eax, 127
        ret

但是如果我将其设置为零,编译器将创建一个完整的代码,其中包含一个循环来计算该数字。我不懂为什么。 单个功能似乎有效,但组合起来却失败了。在我看来,它应该只创建两个带有数字的函数:

test1():
        mov     eax, 127
        ret
test2():
        mov     eax, 127
        ret
c++ c++17 constexpr
1个回答
1
投票

您的缓冲区溢出了。您在调用

string_view::operator[]
后检查索引是否太大:

while (sv[pos] >= '0' && sv[pos] <= '9' && pos < len)

// Fixed:

while (pos < len && sv[pos] >= '0' && sv[pos] <= '9')
© www.soinside.com 2019 - 2024. All rights reserved.