小编gez*_*eza的帖子

使用声明解决歧义

看看这个片段:

namespace A {
int fn();
}
namespace B {
int fn();
}

// namespace Ns {

using namespace A;
using namespace B;
using A::fn;

int z = fn();

// }
Run Code Online (Sandbox Code Playgroud)

这段代码不能编译,因为fn()它不明确int z = fn();

如果我将using's并z放入命名空间(删除两个//),代码将编译.这是为什么?全局命名空间有什么特别之处?

c++

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

为什么"覆盖/最终"需要放在函数声明符之后?

我一直想知道决定,为什么overridefinal必须在成员函数声明符之后:

struct Base {
    virtual void virtFun();
};
struct Foo: Base {
    virtual void virtFun() override;
};
Run Code Online (Sandbox Code Playgroud)

对我来说,放置override/ final代替以下内容更合乎逻辑virtual:

struct Base {
    virtual void virtFun();
};
struct Foo: Base {
    override void virtFun();
};
Run Code Online (Sandbox Code Playgroud)

这背后有原因吗?也许与C++ 11之前有一些兼容性问题?

c++

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

什么意思"xvalue有身份"?

C++ 11引入了新的值类别,其中之一就是xvalue.

它被Stroustrup 解释为(im类别):"它是一个值,它具有身份,但可以从"移动".

另一个来源, cppreference解释说:

glvalue是一个表达式,其评估决定了对象,位域或函数的身份;

并且xvalue是一个glvalue,所以这个陈述也是如此xvalue.

现在,我认为如果有一个xvalue身份,那么我可以检查两个xvalues是否引用同一个对象,所以我取一个地址xvalue.事实证明,不允许:

int main() {
    int a;
    int *b = &std::move(a); // NOT ALLOWED
}
Run Code Online (Sandbox Code Playgroud)

xvalue具有身份意味着什么?

c++ move-semantics xvalue c++11

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

"if constexpr"在模板之外有用吗?

我想if constexpr完全理解.

我理解,如果if constexpr(expr)在模板中使用,并且expr依赖于模板参数,那么在实例化期间,只有一个then/ else分支将被实例化,另一个将被丢弃.

我有两个问题:

  • 是真的,如果expr不依赖于模板参数,那么if constexpr(expr)将不会丢弃任何分支?如果是,标准在哪里这样说?我没有看到标准有什么例外,丢弃只在expr依赖时发生.
  • if constexpr模板以外有用吗?如果是,这有什么用例?你能举出一些例子来了解它的用处吗?

c++ constexpr c++17 if-constexpr template-instantiation

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

Constexpr构造函数无法满足要求,但仍然是constexpr.为什么?

该标准说明了dcl.constexpr/6中的模板constexpr函数/构造函数:

如果constexpr函数模板的实例化模板特化或类模板的成员函数无法满足constexpr函数或constexpr构造函数的要求,那么该特化仍然是constexpr函数或constexpr构造函数,即使调用这样的函数不能出现在常量表达式中.如果模板的特化不满足constexpr函数或constexpr构造函数在被视为非模板函数或构造函数时的要求,则模板格式错误,无需诊断.

有趣的是:

无法满足... constexpr构造函数的要求,该特化仍然是... constexpr构造函数

因此,即使构造函数被标记constexpr,也不能在常量表达式中使用它.

为什么存在这个规则?constexpr当功能不满足要求时,为什么不删除?

目前的行为在两个方面很糟糕:

  • 非constexpr-ness不是在最近的可能位置捕获,而是在实际的constexpr表达式中使用它.所以我们必须找到有问题的部分,在那里constexpr默默地删除.
  • 一个对象,打算静态初始化(因为它有一个constexpr构造函数),将动态初始化,没有任何错误/警告(因为构造函数不是"真正"constexpr).

这条规则是否有一些优点,这可以平衡它的缺点?

c++ language-lawyer c++17

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

什么时候sizeof(size_t)和sizeof(ptrdiff_t)会有所不同?

什么时候可以sizeof(size_t)sizeof(ptrdiff_t)不同?

这有什么现实世界的例子吗?


注意,我知道所有标准都说这些类型是实现定义的.但是,所有的实现,我知道,sizeof(size_t)sizeof(ptrdiff_t)平等.也许是因为一些奇怪(或不那么奇怪)的原因,它们可能会有所不同.

看起来,这sizeof(ptrdiff_t)<sizeof(size_t)不是一个非常有用的情况,因为对于大型数组,指针算法将非常有限.

另一种情况sizeof(ptrdiff_t)>sizeof(size_t)可能稍微有用,因为所有指针减法都将在数组上定义(如果有一个更大的数组PTRDIFF_MAX,则将为所有远程元素定义指针减法,与通常的情况相反sizeof(ptrdiff_t)==sizeof(size_t)).有没有真正的实现呢?这种方法是否还有其他有用的属性?

c++

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

布局兼容类型的目的是什么?

该标准定义了两种类型的布局兼容性.但是,我没有看到标准中的任何地方,当两种类型的布局兼容时后果是什么.似乎布局兼容是一种在任何地方都不使用的定义.

布局兼容的目的是什么?

注意:据说,它可能意味着类型具有相同的布局(offsetof对于每个相应的成员是相同的),因此,例如,对于简单的可复制类型,可以在它们之间复制基础字节.但是我没有在标准中看到这样的东西.

c++ struct memory-layout language-lawyer c++17

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

获得接近2次幂的快速方法(浮点数)

在数值计算中,通常需要将数字缩放到安全范围内.

例如,计算欧几里德距离:sqrt(a^2+b^2).在这里,如果幅度a还是b过小/大,则溢/上溢可能发生.

解决此问题的常用方法是将数字除以最大幅度数.但是,这个解决方案是:

  • 慢(分裂很慢)
  • 造成一点额外的不准确

所以我认为不是除以最大幅度数,而是将它乘以一个接近2次幂的倒数.这似乎是一个更好的解决方案,如:

  • 乘法比除法快得多
  • 准确度更高,因为乘以2的幂是精确的

所以,我想创建一个小实用程序函数,它有一个像这样的逻辑(通过^,我的意思是取幂):

void getScaler(double value, double &scaler, double &scalerReciprocal) {
    int e = <exponent of value>;
    if (e<-1022) { scaler=2^-1022; scalerReciprocal = 2^1022; }
    } else if (e>1022) { scaler=2^1022; scalerReciprocal = 2^-1022; }
    } else { scaler=2^e; scalerReciprocal = 2^(2046-e); }
}
Run Code Online (Sandbox Code Playgroud)

这个函数应该返回一个标准化的scaler&scalerReciprocal,两个都是2的幂数,scaler它接近于value,并且scalerReciprocal是它的倒数scaler.

为最大允许指数scaler/ scaleReciprocal-1022..1022(我不想用低于正常工作scaler,为次正规数可能会很慢). …

c++ floating-point x86 ieee-754

6
推荐指数
2
解决办法
310
查看次数

优化标签(空结构)函数参数的处理

在某些情况下,我们使用标签来区分函数。标签通常是一个空结构:

struct Tag { };
Run Code Online (Sandbox Code Playgroud)

假设我有一个使用此标签的函数:

void func(Tag, int a);
Run Code Online (Sandbox Code Playgroud)

现在,我们调用这个函数:

func(Tag(), 42);
Run Code Online (Sandbox Code Playgroud)

并检查生成的 x86-64 反汇编,godbolt

mov     edi, 42
jmp     func(Tag, int)            # TAILCALL
Run Code Online (Sandbox Code Playgroud)

没关系,标签得到了完全优化:没有为其分配寄存器/堆栈空间。

但是,如果我查看其他平台,就会发现该标签存在一些。

在 ARM 上,r0用作标签,并且它被归零(似乎没有必要):

mov     r1, #42
mov     r0, #0
b       func(Tag, int)
Run Code Online (Sandbox Code Playgroud)

对于 MSVC,ecx被用作标记,并且它是从堆栈中“初始化”的(同样,似乎没有必要):

movzx   ecx, BYTE PTR $T1[rsp]
mov     edx, 42                             ; 0000002aH
jmp     void func(Tag,int)                 ; func
Run Code Online (Sandbox Code Playgroud)

我的问题是:是否有一种标签技术在所有这些平台上都得到了同样的优化?


注意:我没有找到 SysV ABI 指定可以在参数传递时优化空类的地方...(甚至,Itanium C++ ABI说:“空类的传递与普通类没有什么不同”。)

c++ arm x86-64 abi calling-convention

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

为什么在某些情况下,cv-qualifiers从函数返回类型中删除?

看这个简单的例子:

template <typename T>
const T const_create() {
    return T();
}

struct Foo { };

int main() {
    auto &x = const_create<Foo>(); // compiles
    // auto &x = const_create<int>(); // doesn't compile
}
Run Code Online (Sandbox Code Playgroud)

为什么版本可以Foo编译,而int不能编译?换句话说,为什么const要从返回类型中删除const_create<int>?它的工作方式就像它返回一样int,不是const int。这不是语言上的矛盾吗?

标准在哪里规定这种行为?

c++ const value-categories

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