gpt4 book ai didi

c++ - 在编译时拆分字符串会在不同的编译器上产生不同的结果

转载 作者:太空狗 更新时间:2023-10-29 23:10:50 28 4
gpt4 key购买 nike

我试图在编译时拆分一个字符串。我定义了一个函数 split 就像

#include <array>
#include <string_view>

template <std::size_t N>
constexpr std::array<std::string_view, N> split(std::string_view str)
{
std::array<std::string_view, N> arr{};
std::size_t start = 0, end = 0;

for (std::size_t i = 0; i < N && end != std::string_view::npos; i++)
{
end = str.find_first_of(',', start);
arr[i] = str.substr(start, end - start);
start = end + 1;
}

return arr;
}

给定如下用法:

constexpr std::string_view str = "one,two,three,four,five";
constexpr std::array<std::string_view, 5> arr = split<5>(str);

msvc 和 gcc 都可以编译。然而 clang 已经拒绝了这段代码说 std::string_view::find_first_of 不会导致常量表达式(这是编译器错误吗?)。

当我测试结果时:

int main() 
{
std::cout << str << "\n\n";

for (auto i = 0; i < arr.size(); i++)
std::cout << arr[i] << "\n";

return 0;
}

msvc 打印

one,two,three,four,five

one
two
thr
e,f
ur,

虽然 gcc 给了我预期的结果

one,two,three,four,five                                                                                                                                                           

one
two
three
four
five

我添加了第二个拆分函数,它与原始函数相同,只是它在拆分函数内打印出中间子字符串。在这种情况下,msvc 和 gcc 都打印相同的结果,这是上面的预期结果。

为什么结果不同?我在某处调用了 UB 吗?

完整代码可见here

编辑

看起来这是 msvc 中的一个错误。在运行时调用该函数会产生预期的结果:

int main() 
{
std::cout << str << "\n\n";

for (auto i = 0; i < arr.size(); i++)
std::cout << arr[i] << "\n";

auto arr2 = split<5>(str);
for (auto i = 0; i < arr2.size(); i++)
std::cout << arr2[i] << "\n";

return 0;
}

编辑2

当 msvc 为常量表达式运行解释器时,它看起来实际上存在一个错误。我添加了另一个函数来访问函数外部的变量:

constexpr decltype(split<5>(str)) arr = split<5>(str);
constexpr decltype(split_sizes<5>(str)) arr_sizes = split_sizes<5>(str);

template <std::size_t N>
constexpr std::array<std::array<std::size_t, 3>, N> split_sizes(std::string_view str)
{
std::array<std::array<std::size_t, 3>, N> arr{};
std::size_t start = 0, end = 0;

for (std::size_t i = 0; i < N && end != std::string_view::npos; i++)
{
end = str.find_first_of(',', start);
auto sub = str.substr(start, end - start);
arr[i] = { sub.length(), start, end };
start = end + 1;
}

return arr;
}

int main()
{
for (auto i = 0; i < arr.size(); i++)
std::cout << arr[i] << "\tlen=" << arr_sizes[i][0] << " start=" << arr_sizes[i][1] << " end=" << arr_sizes[i][2] << "\n";

std::cout << "\n";
auto arr2 = split<5>(str);
auto arr_sizes2 = split_sizes<5>(str);

for (auto i = 0; i < arr2.size(); i++)
std::cout << arr2[i] << "\tlen=" << arr_sizes2[i][0] << " start=" << arr_sizes2[i][1] << " end=" << arr_sizes2[i][2] << "\n";

return 0;
}

在 msvc 上给出以下结果:

one,two,three,four,five

one len=3 start=0 end=3
two len=3 start=4 end=7
thr len=3 start=8 end=11
e,f len=3 start=12 end=15
ur, len=3 start=16 end=19

one len=3 start=0 end=3
two len=3 start=4 end=7
three len=5 start=8 end=13
four len=4 start=14 end=18
five len=4 start=19 end=18446744073709551615

Here是更新后的完整代码的链接。

最佳答案

这实际上是一个编译器错误。我不知道究竟是什么导致了这个错误,但它在 std::string_view::find_first_of 中。奇怪的是,这个错误只发生在不断评估期间(在编译时)。据我所知,此函数的运行时行为符合预期。

下面是 split 的工作实现:

template <std::size_t N>
constexpr std::array<std::string_view, N> split(std::string_view str)
{
std::array<std::string_view, N> arr{};
std::size_t start = 0, end = 0;

for (std::size_t i = 0; i < N && end != std::string_view::npos; i++)
{
end = std::string_view::npos;
for (std::size_t j = start; j < str.length(); j++)
{
if (str[j] == ',')
{
end = j;
break;
}
}

arr[i] = str.substr(start, end - start);
start = end + 1;
}

return arr;
}

编辑

事实证明,与 gcc 和 clang 相比,msvc 在评估常量表达式方面非常糟糕。我发现许多其他场景(围绕 std::string_view)也无法编译。

关于c++ - 在编译时拆分字符串会在不同的编译器上产生不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54563090/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com