小编gez*_*eza的帖子

如果类型相同,则对象地址背后的原因必须不同,但如果类型不同,则地址可以相同

我们有空的基类优化.看看这两种情况:

案例A.

struct Empty1 { };
struct Empty2 { };
struct One: Empty1, Empty2 { };
Run Code Online (Sandbox Code Playgroud)

这里sizeof(One)是1.地址Empty1Empty2是相同的.

案例B

struct Empty { };
struct Empty1: public Empty { };
struct Empty2: public Empty { };
struct Two: Empty1, Empty2 { };
Run Code Online (Sandbox Code Playgroud)

这里sizeof(Two)是2.地址Empty1Empty2不同,因为它们都有Empty(并且这些Empty地址应该有不同的地址).

为什么标准允许为不同类型使用相同的地址,但不允许使用相同的类型?这条规则避免了什么问题?

如果我创建一个tuple所有空成员都具有相同地址(无论其类型)的实现,我将遇到什么问题?

c++

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

如何拥有类似于 unsigned char 的类型,但不允许别名?

我想要一个类型,如下所示unsigned char

\n\n
    \n
  • 大小为 1
  • \n
  • 可以为其分配整数值(无需任何强制转换)
  • \n
  • 允许位操作
  • \n
  • 算术是允许的,但不是必须的
  • \n
  • 未签名
  • \n
  • 可以简单地复制
  • \n
\n\n

但是,与 不同的是unsigned char,它不允许使用别名。我的意思是,一种没有例外的类型[basic.lval/11.8]

\n\n
\n

如果程序尝试通过以下类型之一以外的泛左值访问对象的存储值,则行为未定义:

\n\n

[...]

\n\n
    \n
  • 一个 char,无符号字符或 std\xe2\x80\x8b::\xe2\x80\x8bbyte 类型。
  • \n
\n
\n\n

有可能有这样的类型吗?

\n\n

原因是:我几乎从不使用unsigned char\ 的别名属性。因此,我想使用一种类型,它不会阻止某些类型的优化(注意,我问这个问题是因为我实际上有一些函数,由于允许别名,因此没有很好地优化)的财产unsigned char)。因此,我希望有一种类型能够满足这一点:“不要为不使用的东西付费”。

\n\n
\n\n

这是一个unsigned char阻止优化的示例:使用此指针会导致热循环中奇怪的去优化

\n

c++ c++17

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

如何尽早捕获浮点错误(就在发生的地方)?

在开发大量浮点代码时,启用 FPU 异常非常有用。当运算结果为 NaN/inf 时,我们可以立即捕获它。

例如,在 Linux 上,我可以通过以下方式启用此功能:

feenableexcept(FE_DIVBYZERO|FE_INVALID|FE_OVERFLOW);
Run Code Online (Sandbox Code Playgroud)

在 SSE 出现之前,这种技术非常有效。然而,今天,对于 SSE,这与-ffast-math(或其他编译器的其他等效选项)发生冲突。

原因之一是 sqrt,因为 sqrt 是作为x*rsqrt(x). x当为零时,这会产生异常。当禁用异常时,这不是问题,因为 sqrt 函数可以处理此问题。

因此,我无法因此启用异常(也许还有其他原因)。

您有什么建议,如何在浮点错误发生的地方尽早捕获浮点错误(我不希望 NaN 传播,并且我也想捕获溢出到无穷大)(如果-ffast-math启用)?

c++ floating-point

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

针对编译时常量优化的函数

假设我有一个向量长度计算函数,它有一个附加inc参数(这告诉相邻元素之间的距离)。一个简单的实现是:

float calcLength(const float *v, int size, int inc) {
    float l = 0;

    for (int i=0; i<size*inc; i += inc) {
        l += v[i]*v[i];
    }
    return sqrt(l);
}
Run Code Online (Sandbox Code Playgroud)

现在,calcLength可以使用两种inc参数进行调用:何时inc在编译时已知,何时未知。我想要一个calcLength针对常见编译时值inc(如 1)的优化版本。

所以,我会有这样的东西:

template <int C>
struct Constant {
    static constexpr int value() {
        return C;
    }
};

struct Var {
    int v;

    constexpr Var(int p_v) : v(p_v) { }

    constexpr int value() const {
        return v;
    }
}; …
Run Code Online (Sandbox Code Playgroud)

c++ c++17 c++20

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

使用constinit变量初始化constexpr变量

看这个小例子:

constinit int a = 0;
constexpr int b = a;
Run Code Online (Sandbox Code Playgroud)

clang不会编译它(godbolt):

2:15:错误:constexpr变量“ b”必须由常量表达式初始化

这是正确的诊断程序吗?

如果是,标准为何不允许这样做?我了解,该a值可能会在运行期间(甚至在动态初始化期间)发生变化,但是在常量初始化时,其值是已知的,因此可以将其用于初始化b

c++ c++20

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

std::construct_at 哪个默认初始化?

std::construct_at相当于

template<class T, class... Args>
constexpr T* construct_at( T* p, Args&&... args ) {
    return ::new (const_cast<void*>(static_cast<const volatile void*>(p)))
        T(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

除了construct_at可以用于常量表达式的求值之外。

正如你所看到的,如果没有args给出,它将对对象进行值初始化。有没有办法实现默认初始化?调用相当于::new (p) T;(注意缺少括号)。

换句话说,是否可以使用可在常量表达式中使用的放置 new 来执行默认初始化?

c++ c++20

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

数组与指针函数参数,有趣的 MSVC 行为

我注意到 MSVC 的一个有趣行为:具有数组参数的函数与具有指针参数的函数的损坏方式不同。

void foo(double a[3]);
Run Code Online (Sandbox Code Playgroud)

被破坏为?foo@@YAXQEAN@Z. 如果我将参数类型分解回来,它就是double * const(这就是编译器抱怨的,godbolt)。另一方面,

void foo(double *a);
Run Code Online (Sandbox Code Playgroud)

被破坏为?foo@@YAXPEAN@Z,破坏后的参数类型为double *。请注意损坏名称中的Q/差异。P这不仅仅是表面上的差异,如果函数定义和声明在这方面不匹配,我们会收到链接器错误。

这种行为是否符合标准?甚至,顶级const修饰符对链接器有意义吗?这是什么意思?

c++ visual-c++ language-lawyer

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

为什么我们没有偏移量适用于所有类型(具有虚拟继承的类型除外)?

目前,offsetof仅适用于标准布局类型.但是,我从来没有理解这个限制.当然,对于具有虚拟继承的类型,offsetof无法工作.但对于没有虚拟继承的类型,它可以.我知道,该标准允许非标准布局类型为每个实例具有不同的成员偏移量.但是,我从来没有听说过任何使用它的编译器实现.为什么会这样做?

我所知道的所有编译器,对于没有虚拟继承的类型,成员的偏移量是编译时常量.

所以问题是:

  • 是否有任何编译器,其成员的偏移量不是编译时常量(对于没有虚拟继承的类型)?
  • 委员会为何不放宽要求offsetof

(我在stackoverflow中已经阅读了很多相关的答案,并在各个地方进行了讨论,但我还没有找到原因).

c++

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

是否可以有一个只能通过 ADL 找到的非友元函数?

C++ 有一个特性,类内定义的友元函数只能通过 ADL(参数相关查找)找到:

struct Foo {
    friend void fn(Foo) { } // fn can only be called by ADL, it won't be found by other lookup methods
};
Run Code Online (Sandbox Code Playgroud)

对于非友元函数是否可以实现相同的效果?我问这个问题是因为有时,我希望拥有“仅由 ADL 找到”的功能,但我实际上并不需要朋友访问类内部。

(还有一个有点固执己见的问题:如果这是不可能的,那么原因是什么?这个“仅由 ADL 发现”规则是故意设计到语言中的吗?)

c++ declaration friend-function name-lookup unqualified-name

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

在转换运算符不明确时选择它们

我有两种类型:

struct A { };
struct B { };
Run Code Online (Sandbox Code Playgroud)

我有功能AB:

void fnA(A); // there are a lot of these functions
void fnB(B);
Run Code Online (Sandbox Code Playgroud)

我有一个类型,可转换为AB:

struct Foo {
    operator A();
    operator B();
};
Run Code Online (Sandbox Code Playgroud)

所以,我可以打电话fnAfnB:

fnA(Foo()); // fine
fnB(Foo());
Run Code Online (Sandbox Code Playgroud)

现在,我有重载功能:

void fn(A);
void fn(B);
Run Code Online (Sandbox Code Playgroud)

我不能打电话给他们Foo,因为它含糊不清:

fn(Foo()); // ambiguous, which fn is called
Run Code Online (Sandbox Code Playgroud)

我希望fn(A)在这种情况下被召唤.

我可以添加第三个fn重载:

inline void fn(Foo foo) {
    fn(A(foo));
}
Run Code Online (Sandbox Code Playgroud)

但我不喜欢这种方式,因为我有很多fn功能,而且我不想大大增加功能的数量(我有fn …

c++

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