以下代码生成的程序集在使用-O3. 为了完整起见,代码始终在 GCC 13.2 中执行 SIMD,而从不在 clang 17.0.1 中执行 SIMD。
#include <array>
__attribute__((noinline)) void fn(std::array<int, 4>& lhs, const std::array<int, 4>& rhs)
{
for (std::size_t idx = 0; idx != 4; ++idx) {
lhs[idx] = lhs[idx] + rhs[idx];
}
}
Run Code Online (Sandbox Code Playgroud)
这是Godbolt 中的链接。
这是 GCC 12.3 的实际汇编(使用 -O3):
fn(std::array<int, 4ul>&, std::array<int, 4ul> const&):
lea rdx, [rsi+4]
mov rax, rdi
sub rax, rdx
cmp rax, 8
jbe .L2
movdqu xmm0, XMMWORD PTR [rsi]
movdqu xmm1, XMMWORD PTR [rdi]
paddd …Run Code Online (Sandbox Code Playgroud) boost::join在混合 的输出时,我遇到了意外的行为std::views::transform(如下所示)。编译器不会发出任何警告。幸运的是,地址清理程序可以检测到get2b().
该get1b()函数遵循与 相同的模式get2b(),但该代码工作正常。考虑到 UB 的可能性,我如何确定构造的范围是合法的?我偏执的一面想get1b()写成return std::move(rng) | ...。
https://www.godbolt.org/z/Y77YW3jYb
#include <array>
#include <ranges>
#include <algorithm>
#include <iostream>
#include <iterator>
#include "boost/range/join.hpp"
#include "boost/range/adaptor/transformed.hpp"
inline auto square = [](int x) { return x*x; };
struct A {
std::array<std::vector<int>, 3> m_data{ std::vector{1, 2}, std::vector{3, 4, 5}, std::vector{6} };
auto join1() const { return m_data | std::views::join; }
auto join2() const { return boost::join(m_data[0], boost::join(m_data[1], m_data[2])); }
auto get1a() …Run Code Online (Sandbox Code Playgroud) 我最近一直在对范围和视图进行一些性能评估。我发布了一个简单的示例(也在https://www.godbolt.org/z/7ThxjKafc),其中汇编的差异比我预期的要显着得多。使用最新的 GCC 和 -O3,
sum_array包含 31 条指令和 8 个跳转。sum_vec包含 12 条指令和 2 个跳转。鉴于 的大小m_array在编译时已知,我预计这两个函数的汇编几乎相同。我是否应该期望优化编译器在未来版本中得到改进,或者在如何std::views::join指定方面是否存在一些基本限制?
#include <array>
#include <vector>
#include <ranges>
struct Foo {
auto join() const { return m_array | std::views::join; }
auto direct() const { return std::views::all(m_array[0]); }
std::array<std::vector<int*>, 1> m_array;
};
__attribute__((noinline)) int sum_array(const Foo& foo)
{
int result = 0;
for (int* val : foo.join())
result += *val;
return result;
}
__attribute__((noinline)) int sum_vec(const Foo& …Run Code Online (Sandbox Code Playgroud) 我的应用程序使用协议缓冲区并具有大量(1 亿)条简单消息。基于 callgrind 分析,正在为每个实例进行内存分配和释放。
考虑以下代表性示例:
// .proto
syntax = "proto2";
package testpb;
message Top {
message Nested {
optional int32 val1 = 1;
optional int32 val2 = 2;
optional int32 val3 = 3;
}
repeated Nested data = 1;
}
// .cpp
void test()
{
testpb::Top top;
for (int i = 0; i < 100'000; ++i) {
auto* data = top.add_data();
data->set_val1(i);
data->set_val2(i*2);
data->set_val3(i*3);
}
std::ofstream ofs{"file.out", std::ios::out | std::ios::trunc | std::ios::binary };
top.SerializeToOstream(&ofs);
}
Run Code Online (Sandbox Code Playgroud)
更改实现以使内存分配数量与实例数量不成线性关系的最有效选项是什么Nested?
代码粘贴在这里 & https://www.godbolt.org/z/qszqYsT4o
我试图提供boost::adaptors::indexed与 c++20 视图兼容的功能。我的主要用例是std::vector,但我肯定更喜欢通用的解决方案。我惊讶地发现它std::views::keys没有按预期正确提取第一个元素。
对于 GCC 10.3, 的输出rng1是垃圾并且rng2符合预期。GCC 10.4+ 工作正常。最新版本的 clang 无法编译代码。
问题:
std::views::keys支持任何pair/tuple类型,还是我的代码UB?std::span一会儿,但似乎无法让它自然地发挥作用。注意:如果有的话我很乐意使用std::views::zip。std::views::iota#include <vector>
#include <ranges>
#include <iostream>
template <typename T>
using IndexValuePair = std::pair<std::size_t, std::reference_wrapper<T>>;
template <typename T, typename Allocator>
auto make_indexed_view(std::vector<T, Allocator>& vec)
{
auto fn = [&vec](T& val) {
return IndexValuePair<T>{static_cast<std::size_t>(&val - vec.data()), val};
};
return std::views::all(vec) | std::views::transform(fn);
} …Run Code Online (Sandbox Code Playgroud) cppreference表示std::thread::id只有 1 个构造函数。 libstdc++包含以下附加公共构造函数:
explicit id(native_handle_type __id) : _M_thread(__id) { }
Run Code Online (Sandbox Code Playgroud)
'cppreference' 是否已过时,或者此构造函数不是标准的一部分?如果它不是标准的一部分,那么为什么它会被公开,因为它std::thread是 的朋友std::thread::id?
是否有任何标准功能可以创建所有对的范围/视图?以下代码说明了我要创建的视图:
std::unordered_map<std::string, std::vector<int>> m{{"Foo", {1,2}}, {"Hello", {4,5}}};
auto view = ???;
std::vector<std::pair<std::string, int>> v{view.begin(), view.end()};
std::vector<std::pair<std::string, int>> out1{{"Foo", 1}, {"Foo", 2}, {"Hello", 4}, {"Hello", 5}};
std::vector<std::pair<std::string, int>> out2{{"Hello", 4}, {"Hello", 5}, {"Foo", 1}, {"Foo", 2}};
assert(v == out1 || v == out2);
Run Code Online (Sandbox Code Playgroud)
注意:编写一个嵌套的 for 循环来迭代此结构很简单。
请参阅下面的代码(也可在此处https://www.godbolt.org/z/hvnvEv1ar)。rng如果我取消注释或的约束,代码将无法编译pair。我觉得我错过了一些微不足道的东西,但我无法弄清楚为什么不满足约束。
#include <vector>
#include <ranges>
#include <utility>
template <typename T>
struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T>
inline constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value;
template <typename T>
concept ReferenceWrapper = is_reference_wrapper_v<T>;
template <typename T>
concept ReferenceWrapperPair = requires(const T& t) {
{ t.first } -> ReferenceWrapper;
{ t.second } -> ReferenceWrapper;
};
template <typename T>
concept ReferenceWrapperPairRange =
std::ranges::range<T> && ReferenceWrapperPair<std::ranges::range_value_t<T>>;
int main()
{
std::vector<std::pair<int, int>> …Run Code Online (Sandbox Code Playgroud) std::ranges::range在 C++20 之前,当需要将a 作为参数时,有必要在模板函数中使用转发引用。由于 C++20 中提供了概念,因此现在可以将按std::ranges::view值传递给泛型函数。根据标准,视图是一个范围。
考虑以下代码。
#include <vector>
#include <ranges>
#include <iterator>
#include <iostream>
template <std::ranges::range Range>
void fn1(Range range) // intentionally not a forwarding reference
{
for (auto& elem : range) {
++elem;
}
}
template <std::ranges::view View>
void fn2(View view)
{
for (auto& elem : view) {
++elem;
}
}
int main()
{
std::vector<int> v{1,2,3};
fn1(v); // doesn't increment, since a copy of 'v' is used in 'fn1'.
/* fn2(v); // fails to compile, …Run Code Online (Sandbox Code Playgroud) std::span考虑这段代码,它尝试为原始指针向量创建各种对象。
#include <vector>
#include <span>
int main()
{
struct S {};
std::vector<S*> v;
std::span<S*> span1{v};
std::span<S* const> span2{v};
std::span<const S* const> span3{v};
std::span<const S*> span4{v};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
span3编译正常,但span4失败并出现以下错误:
<source>: In function 'int main()':
<source>:58:32: error: no matching function for call to 'std::span<const main()::S*>::span(<brace-enclosed initializer list>)'
58 | std::span<const S*> span4{v};
| ^
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:45,
from <source>:5:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/span:231:9: note: candidate: 'template<class _OType, long unsigned int _OExtent> requires (_Extent == std::dynamic_extent || _OExtent == …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++20 ×7
std-ranges ×6
c++-concepts ×2
gcc ×2
boost ×1
libstdc++ ×1
performance ×1
simd ×1
std-span ×1