在某些情况下,您知道某个浮点表达式将始终为非负数。例如,计算一个矢量的长度时,一个做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等的解决方案。
考虑以下简单结构:
struct A
{
float data[16];
};
Run Code Online (Sandbox Code Playgroud)
假设平台上float有32位IEEE754浮点数(如果很重要),那么C ++标准是否可以保证预期的内存布局struct A?如果不是,它将提供什么保证和/或执行保证的方式是什么?
由预期存储器布局我的意思是该结构占用16*4=64在存储器字节,每个连续4字节占用由单个float从data阵列。换句话说,预期的内存布局意味着以下测试通过:
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上通过。我从未遇到过平台和编译器的结合,它们会提供证据证明该测试可能会失败,并且我很想了解它们的存在。
alignas说明符来处理它)。write_bytes(&x, sizeof(A))。data数组以传递这种类型的单个对象,但是对于其中的一系列对象(例如,用于上传矩阵类型的顶点属性),仍然需要特定的内存布局。 …考虑这个代码示例:
#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 /功能?
我有以下代码:
#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下选择的.谁在这里做对了?顺便说一下,我仍然对这个过程的完整描述感兴趣.
我使用以下代码获得"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)
我查看了这个网站和谷歌,找不到可以解决这个问题的解决方案.
任何援助将不胜感激.
谢谢.
Cmake创建了包含opengl的目录,但是opengl头文件位于不同平台(也可能是编译器)上的不同命名子目录:Windows上的gl,Linux上的GL,Mac上的OpenGL(据我所知).因此,添加OPENGL_INCLUDE_DIRECTORY以包含路径并没有多大帮助 - 我仍然必须在我的源中包含(或等等).我该怎么处理呢?
假设我有一个现有项目,并且它是 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)
还有其他方法吗?
考虑以下:
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
考虑以下代码,它使用 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 …
考虑一些抽象类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与签名分开,但它看起来不会很好:(