一般来说,默认构造函数应该是创建空容器的最快方法。这就是为什么我惊讶地发现它比初始化为空字符串文字更糟糕:
#include <string>
std::string make_default() {
return {};
}
std::string make_empty() {
return "";
}
Run Code Online (Sandbox Code Playgroud)
编译为:(clang 16,libc++)
make_default():
mov rax, rdi
xorps xmm0, xmm0
movups xmmword ptr [rdi], xmm0
mov qword ptr [rdi + 16], 0
ret
make_empty():
mov rax, rdi
mov word ptr [rdi], 0
ret
Run Code Online (Sandbox Code Playgroud)
请参阅编译器资源管理器中的实时示例。
请注意,返回{}总共将 24 个字节归零,但返回""仅将 2 个字节归零。怎么会return "";好很多呢?
从 C++11 开始,我们可以在编译时进行浮点数学运算。C++23 和 C++26 添加了constexpr一些函数,但不是全部。
constexpr一般来说,浮点数学很奇怪,因为结果并不完全准确。然而,constexpr代码应该始终提供一致的结果。C++ 如何解决这个问题?
constexpr浮点数学
是如何工作的?constexpr,而其他功能则不然(例如std::nearbyint)我有以下 C/C++ 函数:
unsigned div3(unsigned x) {
return x / 3;
}
Run Code Online (Sandbox Code Playgroud)
使用 clang 10 at编译时-O3,结果为:
div3(unsigned int):
mov ecx, edi # tmp = x
mov eax, 2863311531 # result = 3^-1
imul rax, rcx # result *= tmp
shr rax, 33 # result >>= 33
ret
Run Code Online (Sandbox Code Playgroud)
我所理解的是:除以 3 相当于乘以乘法逆 3 -1 mod 2 32,即 2863311531。
不过还是有些不明白的地方:
ecx/rcx呢?我们不能乘rax用edi直接?eaxand不是更快ecx吗?imul …在我的 Fedora 34 环境(g++)中,std::accumulate定义为:
template<typename ITER, typename T>
constexpr inline T accumulate(ITER first, ITER last, T init)
{
for (; first != last; ++first)
init = std::move(init) + *first; // why move ?
return init;
}
Run Code Online (Sandbox Code Playgroud)
如果表达式init + *first已经是右值,那么 的目的是什么std::move?
我想测试一个类型是否可以传递给某个函数,但我想在函数查找上使用 ADL 并包含来自某个命名空间的函数。
考虑这段代码:
#include <utility>
#include <vector>
template<class T>
concept Swappable = requires(T& a, T& b)
{
swap(a,b);
};
static_assert(Swappable<std::vector<int>>); // #1
static_assert(Swappable<int>); // #2
Run Code Online (Sandbox Code Playgroud)
#1 成功,它发现std::swapbecausestd是 的关联命名空间std::vector<int>。但 #2 失败了,内置类型没有关联的命名空间。
我该怎么写这样的东西:
template<class T>
concept Swappable = requires(T& a, T& b)
{
using std::swap; // illegal
swap(a,b);
};
Run Code Online (Sandbox Code Playgroud)
AFAIK,您不允许在 require 表达式中使用 using 声明。
(注意,虽然对此有一个完美的标准 C++ 概念,但std::swappable此示例swap仅用于说明。我并不是特别想测试某些东西是否实际上是可交换的,我只是想找到一种方法来实现这样的概念其中自定义函数在已知命名空间中具有默认实现,但可能在关联的命名空间中具有重载。)
编辑作为一种解决方法,我可以在一个单独的名称空间中实现这个概念,其中的名称被拉入。对此不太满意,但它有效。
namespace detail
{
using std::swap;
template<class T>
concept Swappable = …Run Code Online (Sandbox Code Playgroud) 这是来自: https: //github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/include/std/type_traits
template<typename _Xp, typename _Yp>
using __cond_res
= decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()());
...
template<typename _Tp1, typename _Tp2>
struct __common_reference_impl<_Tp1, _Tp2, 3,
void_t<__cond_res<_Tp1, _Tp2>>>
{ using type = __cond_res<_Tp1, _Tp2>; };
Run Code Online (Sandbox Code Playgroud)
我想弄清楚什么_Xp(&)()是 - 它是函数调用签名吗?即构造函数?确实没有意义。那里似乎有一个匿名变量名,即:
_Xp(&anon)()
Run Code Online (Sandbox Code Playgroud)
我仍然无法理解它,而且过去 34 年我一直在编写 C++ 代码。
任何解释表示赞赏。谢谢。
在 C++23 中,该[[assume(expression)]]属性使得如果表达式为false,则行为未定义。例如:
int div(int x, int y) {
[[assume(y == 1)]];
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
y这会编译成与始终相同的代码1。
div(int, int):
mov eax, edi
ret
Run Code Online (Sandbox Code Playgroud)
但是,如果存在另一级别的未定义行为,会发生什么情况?
int div(int x, int y) {
[[assume(x / 0 == 1)]];
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
现在假设里面有UB,但是假设没有被评估。这是什么意思?这只是无稽之谈还是编译器可以用这个假设做任何事情?
我有以下代码:
#include <print>
#include <vector>
int main() {
std::vector<int> v{1, 2, 3};
std::println("{}", v);
}
Run Code Online (Sandbox Code Playgroud)
在这产生的众多错误中,有(clang++ -std=c++23 -stdlib=libc++,https://godbolt.org/z/3z9Tseh37):
[...]/format_arg_store.h:167:17: error: static assertion failed due to [...]
167 | static_assert(__arg != __arg_t::__none, "the supplied type is not formattable");
| ^~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
这让我很困惑,因为根据cppreference C++23 编译器支持页面,libc++ 支持std::println并实现P2286: Formatting Ranges。
我做错了什么还是这是标准库错误?
我有四个身份函数,它们基本上什么都不做。只有乘法1才能通过 clang 优化为单个ret语句。
float id0(float x) {
return x + 1 - 1;
}
float id1(float x) {
return x + 0;
}
float id2(float x) {
return x * 2 / 2;
}
float id3(float x) {
return x * 1;
}
Run Code Online (Sandbox Code Playgroud)
以下编译器输出是:(clang 10, at -O3)
.LCPI0_0:
.long 1065353216 # float 1
.LCPI0_1:
.long 3212836864 # float -1
id0(float): # @id0(float)
addss xmm0, dword ptr [rip + .LCPI0_0]
addss xmm0, dword ptr [rip + .LCPI0_1] …Run Code Online (Sandbox Code Playgroud) 如何快速计算任何底数的整数对数,而不仅仅是底数 10?这个问题对于基数 10 有一个非常有效的解决方案,但我想了解如何将其推广到其他基数。
c++ ×10
c++23 ×3
c++20 ×2
compilation ×2
libc++ ×2
assembly ×1
assumption ×1
base ×1
c ×1
c++-concepts ×1
c++17 ×1
c++26 ×1
clang ×1
constexpr ×1
fmt ×1
logarithm ×1
math ×1
optimization ×1
stdmove ×1
stdstring ×1
stdvector ×1
type-traits ×1
x86-64 ×1