小编NoS*_*tAl的帖子

Clang生成的7次比较比8次比较糟糕的代码

clang能够将许多小整数的==比较转换为一条大SIMD指令,这让我很感兴趣,但是后来我注意到了一些奇怪的事情。当我进行7次比较时,Clang生成了“更差”的代码(在我的业余评估中),而当我进行8次比较时,Clang生成了该代码。

bool f1(short x){
    return (x==-1) | (x == 150) |
           (x==5) | (x==64) | 
           (x==15) | (x==223) | 
           (x==42) | (x==47);
}

bool f2(short x){
    return (x==-1) | (x == 150) |
           (x==5) | (x==64) | 
           (x==15) | (x==223) | 
           (x==42);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是这是一个很小的性能错误,或者clang有一个很好的理由不想引入虚拟比较(即假装与7个值之一进行额外的比较),并在代码中使用一个更多的常量来实现它。

Godbolt链接在这里

# clang(trunk) -O2 -march=haswell
f1(short):
    vmovd   xmm0, edi
    vpbroadcastw    xmm0, xmm0             # set1(x)
    vpcmpeqw        xmm0, xmm0, xmmword ptr [rip + .LCPI0_0]  # 16 bytes = 8 shorts
    vpacksswb       xmm0, xmm0, xmm0
    vpmovmskb       eax, …
Run Code Online (Sandbox Code Playgroud)

c++ x86 assembly clang compiler-optimization

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

C++20 中是否有一个浮点数包装器,可以让我默认飞船运算符?

我正在观看“使用 C++20 三路比较 - Jonathan M\xc3\xbcller - Meeting C++ 2019”演讲,其中提到了包含浮点成员的类的问题。

\n\n

问题源于这样一个事实:涉及 NaN 的 IEEE 754 比较很奇怪,并且不提供总排序。\nTalk 提供了一种解决此问题的方法,例如使用Strong_order或在实现 <=> 时手动忽略 NaN 值(假设值永远不是 NaN)。

\n\n

我的问题是,是否有一些库包装器可以让我说“我保证”我的浮点数永远不是 NaN,或者可以对浮点数进行缓慢但有效的比较(更慢但更安全,因为 NaN 现在是有序的)。我的目标是通过使成员漂浮宇宙飞船友好来避免手动实现宇宙飞船(这样我可以默认宇宙飞船)。

\n\n

使用演讲中的例子:

\n\n
// original class\nstruct Temperature{\n    double value;\n};\n\nstruct TemperatureNoNan{\n    std::a_number<double> value; // I promise value will never be NaN\n    // Now spaceship defaulting works\n};\n\nstruct TemperatureStrongO{\n    std::s_ordered<double> value; // I want strong ordering(2 diff NaNs are not the same)\n    // Now spaceship defaulting works\n};\n
Run Code Online (Sandbox Code Playgroud)\n

c++ spaceship-operator c++20

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

C++ 不重载 time 函数所以我们不需要写 NULL 有什么原因吗?

这不是我懒得写

auto t = time(nullptr);
Run Code Online (Sandbox Code Playgroud)

而不是假设

auto t = time();
Run Code Online (Sandbox Code Playgroud)

我最感兴趣的是如果这是可能的,如果是(AFAIK它很容易实现,因为C++支持函数重载)为什么它没有完成。

我知道明显的答案,例如:使用<chrono>,没有人写过提案,但我想知道是否有不同的原因。

我最好的猜测是没有人想弄乱 C 库函数。

PS我知道有些人可能想关闭这个问题过于模糊,但我觉得可以对这个问题给出相对客观的答案。

c++ std

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

std::adjacent_difference 与 std::chrono time_point

考虑以下代码:

int main()
{
    std::vector<std::chrono::steady_clock::time_point> time;
    time.push_back(std::chrono::steady_clock::now());
    std::this_thread::sleep_for(std::chrono::milliseconds(4));
    time.push_back(std::chrono::steady_clock::now());
    std::this_thread::sleep_for(std::chrono::milliseconds(7));
    time.push_back(std::chrono::steady_clock::now());
    std::vector<std::chrono::duration<double>> diffs;
    std::adjacent_difference(time.begin(),time.end(),std::back_inserter(diffs));
}
Run Code Online (Sandbox Code Playgroud)

它无法编译(有关不匹配类型的丑陋模板错误消息)。当我尝试切换到输入错误消息 ( std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>>) 时,错误消息会四处移动。

我的假设是算法不起作用,因为减去 2 个时间点的结果不是时间点,即伪代码中的这行内容是冲突的。

template<class InputIt, class OutputIt>
constexpr // since C++20
OutputIt adjacent_difference(InputIt first, InputIt last, 
                             OutputIt d_first)
{
    if (first == last) return d_first;
 
    typedef typename std::iterator_traits<InputIt>::value_type value_t;
    value_t acc = *first;  
    *d_first = acc; // <-----------------------------------------------------  1
    while (++first != last) {
        value_t val = *first;
        *++d_first = val - std::move(acc); // std::move since C++20 …
Run Code Online (Sandbox Code Playgroud)

c++ c++-chrono c++20

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

这个成员函数选择代码可以在没有 std::invoke 的情况下编写吗?

我试图fn根据某个constexpr值选择一个成员。然后我尝试调用选定的函数,但是我收到了关于如何fn使用不正确的语法调用成员的错误。

error: must use '.*' or '->*' to call pointer-to-member function in
'S::SelectedGetter<&S::fn1, &S::fn2>::fn (...)', e.g. '(... ->*
S::SelectedGetter<&S::fn1, &S::fn2>::fn) (...)'     
    18 |     return SelectedGetter<&S::fn1, &S::fn2>::fn();
Run Code Online (Sandbox Code Playgroud)

我试图称之为“正确”但失败了。最后我使用的是std::invoke,但我想知道这是否可以在没有 的情况下完成std::invoke,只使用“原始”C++ 语法。

#include <algorithm>
#include <type_traits>

static constexpr int number = 18;

struct S
{
    using GetterFn = uint32_t(S::*)() const;
    uint32_t fn1()const {
        return 47;
    }
    uint32_t fn2() const {
        return 8472;
    }

    template <GetterFn Getter1, GetterFn Getter2>
    struct SelectedGetter
    {
        static constexpr …
Run Code Online (Sandbox Code Playgroud)

c++ templates member-function-pointers c++20 std-invoke

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

检查 std::chrono 持续时间是否小于 0 的惯用方法

我知道我能做到

if (timeLeft.count() < 0)
Run Code Online (Sandbox Code Playgroud)

但我想知道最好的方法是什么,因为我也可以这样做:

if (timeLeft<std::chrono::seconds(0)) // or milliseconds or nanonseconds...
Run Code Online (Sandbox Code Playgroud)

注意:我认为这两项检查是相同的,但我不是计时专家。

编辑:完整示例:

#include<chrono>
int main(){
    const std::chrono::nanoseconds timeLeft(-5);
    if(timeLeft<std::chrono::seconds(0)){
        return 47;
    }
}
Run Code Online (Sandbox Code Playgroud)

edit2:潜在的问题std::chrono::seconds(0)是新手程序员可能会认为它涉及舍入,尽管事实并非如此。

c++ c++-chrono c++20

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

为什么 std::any 实现使用 typeid?

即使使用 -fno-rtti 编译,它似乎在 GCC 和 Clang 中std::any 也能正常工作。

在查看 libc++ 源代码时,我发现他们只是使用了一个简单的技巧:

它们获取以任何类型为模板的变量的地址,这就是它们获取唯一 ID 的方式。

但此代码仅在没有打开 RTTI 时才有效。

这让我想知道。他们为什么首先使用 RTTI?为什么不总是使用这个解决方案呢?我不知道为什么typeid比简单的指针(指向每个类型实例化的静态变量)比较更快。

c++ optimization rtti libc++ stdany

5
推荐指数
0
解决办法
448
查看次数

为什么宇宙飞船允许混合比较(不同的模板实例)与无意义的结果?

编辑:这与飞船无关。只是飞船的使用混淆了我代码中的真正问题(详见答案)。

我对这个程序的输出感到惊讶:(如果你喜欢谜题,请随意打开 Godbolt 链接并尝试自己找出原因)

#include <cstdint>
#include <cassert>
#include <compare>
#include <cmath>
#include <iostream>
#include <limits>

template<typename T>
struct TotallyOrdered
{
    T val;
    constexpr TotallyOrdered(T val) :
        val(val) {}
    constexpr operator T() const { return val; }
    constexpr std::strong_ordering operator<=>(TotallyOrdered const& other) const
    {
        if (std::isnan(val) && std::isnan(other.val))
        {
            return std::strong_ordering::equal;
        }
        if (std::isnan(val))
        {
            return std::strong_ordering::less;
        }
        if (std::isnan(other.val))
        {
            return std::strong_ordering::greater;
        }
        if (val < other.val)
        {
            return std::strong_ordering::less;
        }
        else if (val == other.val)
        { …
Run Code Online (Sandbox Code Playgroud)

c++ spaceship-operator c++20

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

可以使用 C++20 范围就地完成字符串修剪吗?

受到可爱的 cppreference用 C++20 进行修剪的示例的启发,我编写了以下代码(我已将返回类型更改为void并将 arg 更改为std::string&,因为我的“问题”(我正在发明问题来学习 C++20)不存在于使用std::string_viewarg 并返回的原始代码std::string)。

void trim(std::string&  in)
{
    auto view
        = std::views::all(in)
        | std::views::drop_while(isspace)
        | std::views::reverse
        | std::views::drop_while(isspace)
        | std::views::reverse;
        std::string result{view.begin(), view.end()};
        in = std::move(result);
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是这不是就位,这意味着创建了新字符串。我可以编写更丑陋的代码来就地执行此操作,并且我知道传统的 C++ 算法不知道容器的存在,但我想知道 C++20 是否有一些技巧使我能够以优雅的方式进行修剪,但也可以就地进行。

这也是我丑陋的就地修剪(不确定它是否正常工作,但想法是它可以就地修剪):

void trim2(std::string& s) {
    // ugly and error prone, but inplace
    const auto it1 = std::ranges::find_if_not(s, isspace);
    const auto it2 = std::ranges::find_if_not(s.rbegin(), s.rend(), isspace);
    const size_t shift = (it1==s.end()) ? 0: std::distance(s.begin(), it1); …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 std-ranges

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

为什么 views::reverse 不适用于 iota_view&lt;int64_t, int64_t&gt;

我有以下 C++ 程序,由于某种原因我不能int64_t用作模板参数。

#include <iostream>
#include <ranges>

template<typename T> 
void fn() {
    for (auto val : std::ranges::iota_view{T{1701}, T{8473}} 
                  | std::views::reverse
                  | std::views::take(5))
    {
        std::cout << val << std::endl;
    }

}

int main()
{
    fn<int16_t>();
    fn<int32_t>();
    // does not compile:
    // fn<int64_t>();
}
Run Code Online (Sandbox Code Playgroud)

这是预期的(我做错了什么),还是只是编译器/标准库中的一些不幸的错误?

注意:当我删除std::views::reverse代码时int64_t也编译。

c++ c++20 std-ranges

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