Mar*_*pel 0 c++ constexpr c++17
我尝试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");
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用编译器资源管理器来编译它: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
Run Code Online (Sandbox Code Playgroud)
但如果我将其设置为零,编译器将创建一个完整的代码,其中包含一个循环来计算该数字。我不懂为什么。单个功能似乎有效,但组合起来却失败了。在我看来,它应该只创建两个带有数字的函数:
test1():
mov eax, 127
ret
test2():
mov eax, 127
ret
Run Code Online (Sandbox Code Playgroud)
创建一个函数constexpr意味着一个函数可能会在编译时被评估。该函数是否在编译时实际求值取决于它是否在常量求值期间被调用。
在您的示例中,您在评估常量的过程中没有调用""_ipv4, 或。getIpVal因此,函数是直接返回答案还是调用循环,取决于编译器进行优化。例如,Clang 优化代码以生成直接返回值的程序集。https://godbolt.org/z/zz3oj3Mor
如果要保证在不断求值期间调用函数,可以将结果分配给变量constexpr,例如
constexpr auto n = getIpVal("127");
Run Code Online (Sandbox Code Playgroud)
现在您将收到一条编译器错误消息:
while (sv[pos] >= '0' && sv[pos] <= '9' && pos < len)
Run Code Online (Sandbox Code Playgroud)
是不正确的。这是因为您sv在检查pos索引是否有效之前要对其进行索引。通常这将是 UB,但是在编译时没有 UB,并且您强制编译器在编译时评估该函数,因此您会得到一个很好的诊断。
保证函数在编译时被调用的另一种方法是使其成为一个consteval函数。但是,此类函数只能在编译时调用,因此如果您需要使用非常量参数(例如从用户处获得的参数)调用此函数,则此函数将不起作用。