我们有空的基类优化.看看这两种情况:
案例A.
struct Empty1 { };
struct Empty2 { };
struct One: Empty1, Empty2 { };
Run Code Online (Sandbox Code Playgroud)
这里sizeof(One)
是1.地址Empty1
和Empty2
是相同的.
案例B
struct Empty { };
struct Empty1: public Empty { };
struct Empty2: public Empty { };
struct Two: Empty1, Empty2 { };
Run Code Online (Sandbox Code Playgroud)
这里sizeof(Two)
是2.地址Empty1
和Empty2
不同,因为它们都有Empty
(并且这些Empty
地址应该有不同的地址).
为什么标准允许为不同类型使用相同的地址,但不允许使用相同的类型?这条规则避免了什么问题?
如果我创建一个tuple
所有空成员都具有相同地址(无论其类型)的实现,我将遇到什么问题?
我想要一个类型,如下所示unsigned char
:
但是,与 不同的是unsigned char
,它不允许使用别名。我的意思是,一种没有例外的类型[basic.lval/11.8]:
\n\n\n如果程序尝试通过以下类型之一以外的泛左值访问对象的存储值,则行为未定义:
\n\n[...]
\n\n\n
\n- 一个 char,无符号字符或 std\xe2\x80\x8b::\xe2\x80\x8bbyte 类型。
\n
有可能有这样的类型吗?
\n\n原因是:我几乎从不使用unsigned char
\ 的别名属性。因此,我想使用一种类型,它不会阻止某些类型的优化(注意,我问这个问题是因为我实际上有一些函数,由于允许别名,因此没有很好地优化)的财产unsigned char
)。因此,我希望有一种类型能够满足这一点:“不要为不使用的东西付费”。
这是一个unsigned char
阻止优化的示例:使用此指针会导致热循环中奇怪的去优化
在开发大量浮点代码时,启用 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
启用)?
假设我有一个向量长度计算函数,它有一个附加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) 看这个小例子:
constinit int a = 0;
constexpr int b = a;
Run Code Online (Sandbox Code Playgroud)
clang不会编译它(godbolt):
2:15:错误:constexpr变量“ b”必须由常量表达式初始化
这是正确的诊断程序吗?
如果是,标准为何不允许这样做?我了解,该a
值可能会在运行期间(甚至在动态初始化期间)发生变化,但是在常量初始化时,其值是已知的,因此可以将其用于初始化b
。
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 来执行默认初始化?
我注意到 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
修饰符对链接器有意义吗?这是什么意思?
目前,offsetof
仅适用于标准布局类型.但是,我从来没有理解这个限制.当然,对于具有虚拟继承的类型,offsetof
无法工作.但对于没有虚拟继承的类型,它可以.我知道,该标准允许非标准布局类型为每个实例具有不同的成员偏移量.但是,我从来没有听说过任何使用它的编译器实现.为什么会这样做?
我所知道的所有编译器,对于没有虚拟继承的类型,成员的偏移量是编译时常量.
所以问题是:
offsetof
?(我在stackoverflow中已经阅读了很多相关的答案,并在各个地方进行了讨论,但我还没有找到原因).
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
我有两种类型:
struct A { };
struct B { };
Run Code Online (Sandbox Code Playgroud)
我有功能A
或B
:
void fnA(A); // there are a lot of these functions
void fnB(B);
Run Code Online (Sandbox Code Playgroud)
我有一个类型,可转换为A
和B
:
struct Foo {
operator A();
operator B();
};
Run Code Online (Sandbox Code Playgroud)
所以,我可以打电话fnA
和fnB
:
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 …