小编lis*_*rus的帖子

如何强制GCC假定浮点表达式为非负数?

在某些情况下,您知道某个浮点表达式将始终为非负数。例如,计算一个矢量的长度时,一个做sqrt(a[0]*a[0] + ... + a[N-1]*a[N-1])(NB:我知道的std::hypot,这是不相关的问题),并且平方根下表达显然是非负的。但是,GCC 为以下输出以下程序集sqrt(x*x)

        mulss   xmm0, xmm0
        pxor    xmm1, xmm1
        ucomiss xmm1, xmm0
        ja      .L10
        sqrtss  xmm0, xmm0
        ret
.L10:
        jmp     sqrtf
Run Code Online (Sandbox Code Playgroud)

也就是说,它将结果x*x与零进行比较,如果结果为非负数,则执行sqrtss指令,否则调用sqrtf

因此,我的问题是:如何强制GCC假定该x*x值始终为非负值,从而跳过比较和sqrtf调用,而无需编写内联汇编?

我想强调的是,我对本地解决方案感兴趣,而不是像-ffast-math-fno-math-errno或那样做-ffinite-math-only(尽管确实可以解决问题,这要归功于ks1322,harold和Eric Postpischil的评论)。

此外,“强制将GCC假定x*x为非负数”应解释为assert(x*x >= 0.f),因此这也排除了x*xNaN 的情况。

我可以使用特定于编译器,特定于平台,特定于CPU等的解决方案。

c++ floating-point assembly gcc micro-optimization

57
推荐指数
3
解决办法
2529
查看次数

具有基本类型的单个数组成员的标准布局结构的保证内存布局

考虑以下简单结构:

struct A
{
    float data[16];
};
Run Code Online (Sandbox Code Playgroud)

我的问题是:

假设平台上float有32位IEEE754浮点数(如果很重要),那么C ++标准是否可以保证预期的内存布局struct A?如果不是,它将提供什么保证和/或执行保证的方式是什么?

预期存储器布局我的意思是该结构占用16*4=64在存储器字节,每个连续4字节占用由单个floatdata阵列。换句话说,预期的内存布局意味着以下测试通过:

static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));
Run Code Online (Sandbox Code Playgroud)

offsetof这里是合法的,因为A是标准布局,请参见下文)

万一这困扰您,测试实际上会通过 gcc 9 HEAD在wandbox上通过。我从未遇到过平台和编译器的结合,它们会提供证据证明该测试可能会失败,并且我很想了解它们的存在。

为什么还要关心:

  • 类似于SSE的优化需要某些内存布局(和对齐方式,我可以在此问题中忽略它,因为可以使用标准alignas说明符来处理它)。
  • 这样的结构的序列化将简单地归结为一个不错的和可移植的write_bytes(&x, sizeof(A))
  • 一些API(例如OpenGL,特别是glUniformMatrix4fv)期望这种确切的内存布局。当然,可以仅将指针传递给data数组以传递这种类型的单个对象,但是对于其中的一系列对象(例如,用于上传矩阵类型的顶点属性),仍然需要特定的内存布局。 …

c++ memory-layout language-lawyer standard-layout

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

使用std :: function重载解析

考虑这个代码示例:

#include <iostream>
#include <functional>

typedef std::function<void()> func1_t;
typedef std::function<void(int)> func2_t;

struct X
{
   X (func1_t f)
   { }

   X (func2_t f)
   { }
};

int main ( )
{
   X x([](){ std::cout << "Hello, world!\n"; });
}
Run Code Online (Sandbox Code Playgroud)

我确信它不应该编译,因为编译器不应该能够选择两个构造函数中的一个.g ++ - 4.7.3显示了这种预期的行为:它表示重载构造函数的调用是不明确的.但是,g ++ - 4.8.2成功编译了它.

这个代码在C++ 11中是正确的还是这个版本的g ++的bug /功能?

c++ lambda overloading c++11

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

C++模板函数重载决策

我有以下代码:

#include <iostream>

template <typename T>
void f (T) { std::cout << "f(T)" << std::endl; }

template <typename T>
void f (bool) { std::cout << "f(bool)" << std::endl; }

int main ( )
{
    f(true);        // #1 prints f(T)
    f<bool>(true);  // #2 prints f(bool)
}
Run Code Online (Sandbox Code Playgroud)

#1行称f(T),虽然#2行调用f(bool).

为什么会这样?选择重载模板函数的规则是什么?

UPDATE

我明白在第一次调用时,编译器T在尝试调用第二个函数时无法推断,因此选择第一个函数.

在第二个调用中,第二个函数被认为是更好的匹配gcc,而第一个函数是在VS2013下选择的.谁在这里做对了?顺便说一下,我仍然对这个过程的完整描述感兴趣.

c++ templates overloading overload-resolution

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

'memcpy'未在此范围内定义

我使用以下代码获得"memcpy未在此范围错误中定义":

CommonSessionMessage::CommonSessionMessage(const char* data, int size) 
    : m_data(new char[size]) {
  memcpy(m_data.get(), data, size);
}
Run Code Online (Sandbox Code Playgroud)

我查看了这个网站和谷歌,找不到可以解决这个问题的解决方案.

任何援助将不胜感激.

谢谢.

c++ linux memcpy

7
推荐指数
2
解决办法
2万
查看次数

CMake:opengl包括dirs在不同平台上的命名方式不同

Cmake创建了包含opengl的目录,但是opengl头文件位于不同平台(也可能是编译器)上的不同命名子目录:Windows上的gl,Linux上的GL,Mac上的OpenGL(据我所知).因此,添加OPENGL_INCLUDE_DIRECTORY以包含路径并没有多大帮助 - 我仍然必须在我的源中包含(或等等).我该怎么处理呢?

opengl cmake include

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

如何从 CMake 生成的构建系统中检索目标属性?

假设我有一个现有项目,并且它是 cmake 配置的构建目录。如果我知道目标名称,如何使用此构建检索某些目标的属性?我尝试创建一个像这样的单独脚本

get_target_property(VAR target property)
Run Code Online (Sandbox Code Playgroud)

但它因错误而失败

Command get_target_property() is not scriptable
Run Code Online (Sandbox Code Playgroud)

还有其他方法吗?

cmake target

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

如何模拟模板别名的推导指南?

考虑以下:

template <typename T, std::size_t N>
struct my_array
{
    T values[N];
};
Run Code Online (Sandbox Code Playgroud)

我们可以为提供扣减指南my_array,例如

template <typename ... Ts>
my_array (Ts ...) -> my_array<std::common_type_t<Ts...>, sizeof...(Ts)>;
Run Code Online (Sandbox Code Playgroud)

现在,假设它my_array<T, 2>具有一些非常特殊的含义(但仅含义是,接口和实现保持不变),所以我们想给它一个更合适的名称:

template <typename T>
using special = my_array<T, 2>;
Run Code Online (Sandbox Code Playgroud)

事实证明,推论指南根本不适用于模板别名,即会产生编译错误:

float x, y;

my_array a { x, y }; // works
special b { x, y }; // doesn't
Run Code Online (Sandbox Code Playgroud)

我们仍然可以说special<float> b并感到高兴。但是,假设这T是一个冗长乏味的类型名称,例如std::vector<std::pair<int, std::string>>::const_iterator。在这种情况下,在此处进行模板参数推导将非常方便。因此,我的问题是:如果我们真的想special成为与(在某种意义上)相等的类型my_array<T, 2>,并且我们真的希望演绎指南(或类似的东西)起作用,那么如何克服这一限制?

对于一个含糊其词的问题,我事先表示歉意。


我提出了两个解决方案,它们都有严重的缺点。

1)special使用相同的接口创建一个独立的无关类,即

template …
Run Code Online (Sandbox Code Playgroud)

c++ templates template-aliases template-argument-deduction c++17

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

range::view::transform 产生一个 InputIterator 阻止使用 std::prev

考虑以下代码,它使用 C++20 中的 Ranges 库:

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
    std::vector<int> v{0,1,2,3,4,5,6,7};

    auto transformed = std::ranges::views::transform(v, [](int i){ return i * i; });

    std::cout << *std::prev(std::end(transformed));
}
Run Code Online (Sandbox Code Playgroud)

得知(至少在 GCC-10.3.0 和 GCC-12.0.0 下)这段代码卡在std::prev.

什么情况是,由于拉姆达不返回左值引用,transformed范围迭代器被列为输入迭代器(参见规则进行iterator_category选择的views::transform)。但是,std::prev 要求迭代器至少是双向迭代器,所以我猜这段代码实际上是UB。在 libstdc++ 中,应用于std::prev输入迭代器会导致此函数

template<typename _InputIterator, typename _Distance>
__advance(_InputIterator& __i, _Distance __n, input_iterator_tag)
{
    // concept requirements
    __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
    __glibcxx_assert(__n >= 0);
    while (__n--)
        ++__i;
}
Run Code Online (Sandbox Code Playgroud)

被调用__n == -1 …

c++ iterator c++20 std-ranges

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

函数签名返回抽象类

考虑一些抽象类A:

class A
{
    virtual void f() = 0;
};
Run Code Online (Sandbox Code Playgroud)

假设我希望声明一个返回此类的函数签名类型:

using Type = A();
Run Code Online (Sandbox Code Playgroud)

鉴于此代码,gcc-4.8.2错误导致错误

error: ‘type name’ declared as function returning an abstract class type
Run Code Online (Sandbox Code Playgroud)

clang-3.3 编译得很好.

我试图谷歌这个问题,但没有找到任何有用的东西.这段代码是否符合标准?如果没有,那么禁止宣布这种签名类型的原因是什么?我只是在声明中看不到任何问题.

免责声明:我打算创建这种类型的实例,我只想宣布描述的签名.

对于那些对这种声明有用的人感兴趣:我有一些工厂容器使用签名,就像Interface(Arguments...)添加新工厂来了解新工厂一样; 实际返回的类型是根据一个单独的traits类确定的,参数由Interface.

显然,我可以将其Interface与签名分开,但它看起来不会很好:(

c++ abstract-class signature language-lawyer

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