小编Mar*_*rkB的帖子

为什么 GCC 生成有条件执行 SIMD 实现的代码?

以下代码生成的程序集在使用-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)

c++ gcc simd auto-vectorization

24
推荐指数
1
解决办法
1116
查看次数

有没有办法确定范围是否正确构建?

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)

c++ boost c++20 std-ranges

7
推荐指数
1
解决办法
156
查看次数

使用 std::views::join 是否存在基本的性能成本?

我最近一直在对范围和视图进行一些性能评估。我发布了一个简单的示例(也在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)

c++ performance gcc c++20 std-ranges

6
推荐指数
0
解决办法
298
查看次数

如何最小化大量消息的协议缓冲区内存分配?

我的应用程序使用协议缓冲区并具有大量(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

c++ protocol-buffers

5
推荐指数
1
解决办法
1021
查看次数

std::views::keys 是否保证能与任何对/元组类型正常工作?

代码粘贴在这里 & 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 无法编译代码。

问题:

  1. 保证std::views::keys支持任何pair/tuple类型,还是我的代码UB?
  2. 鉴于 clang 14.0.0 无法编译,我的代码是否合法 C++?
  3. 在c++20中有没有更好的方法来实现这个功能?我看了std::span一会儿,但似乎无法让它自然地发挥作用。注意:如果有的话我很乐意使用std::views::zipstd::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)

c++ c++20 std-ranges

4
推荐指数
1
解决办法
736
查看次数

libstdc++ 的 std::thread::id 构造函数都符合标准吗?

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

c++ libstdc++

4
推荐指数
1
解决办法
88
查看次数

是否有任何标准功能可以使用容器作为mapped_type 创建地图的扁平视图?

是否有任何标准功能可以创建所有对的范围/视图?以下代码说明了我要创建的视图:

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 循环来迭代此结构很简单。

c++ c++20 std-ranges

3
推荐指数
1
解决办法
688
查看次数

如何为 std::pair 引用包装器的范围定义 C++ 概念?

请参阅下面的代码(也可在此处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)

c++ c++-concepts c++20 std-ranges

3
推荐指数
1
解决办法
283
查看次数

对于函数来说,接受对范围而不是视图的转发引用有好处吗?

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)

c++ c++-concepts c++20 std-ranges

2
推荐指数
1
解决办法
537
查看次数

为什么逻辑常量只能添加到 const 指针的 std::span 中?

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++ c++20 std-span

1
推荐指数
1
解决办法
504
查看次数