考虑以下代码片段:
int main(){
constexpr int x = -1;
if(x >= 0){
constexpr int y = 1<<x;
}
}
Run Code Online (Sandbox Code Playgroud)
GCC 7(可能还有其他版本的GCC)拒绝对此进行编译,并说:
error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]
Run Code Online (Sandbox Code Playgroud)
我可以猜想这可能是从哪里来的:constexpron 的声明y使GCC y在编译时进行评估,而在这里它可能是负数。删除constexpr修复错误。
但是,这是标准的未定义行为吗?条件始终为假,因此y将永远不会使用的值。
在我的实际代码中,x是模板参数,该参数可以为负,也可以不为负。
String并且str都实现Hash,所以我们可以散列它们中的任何一个。似乎拥有和借用的字符串当前哈希为相同的值,因此此断言成功:
use std::hash::Hash;
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
pub fn main() {
let hash1 = {
let x: String = "abc".to_owned();
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
};
let hash2 = {
let x: &str = "abc";
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
};
assert!(hash1 == hash2);
}
Run Code Online (Sandbox Code Playgroud)
我正在写关于这种行为的利用代码raw_entry的API HashMap。具体来说,我使用了一个 HashMap,其中键是枚举,但为了减少冗余分配,我想使用这些枚举的“借用”版本进行查找。
换句话说,在下面的代码中,我确实需要保证两个断言都会成功,而不管使用的是什么Hasher实现。在我看来,这将取决于和的Hash实现提供的保证。Stringstr
use std::hash::Hash;
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
pub fn main() {
{ …Run Code Online (Sandbox Code Playgroud) 在 Rust 中,有两种方法可以从另一个切片更新切片的内容:clone_from_slice()和copy_from_slice(). 这两个函数的行为并不奇怪 - 第一个执行克隆并期望类型实现Clone,而第二个执行复制并期望类型实现Copy。
然而,令我惊讶的是,它的文档是这样clone_from_slice说的:“如果T实现了Copy,使用它可以提高性能copy_from_slice。” 令人惊讶的是,这里应该存在性能差异。如果Timplements Copy,则.clone()要求相当于复制位;但是,由于编译器知道是什么类型T,因此即使我使用clone_from_slice.
那么性能低效从何而来?
我有一个包含 C 和 C++ 文件的 CMake 项目,并且设置了 CI。在 CI 中,我想使用一些附加标志来构建我的项目,以使编译器更加严格,特别是-Wall -Wextra -Werror -pedantic.
为了配置该项目,我目前正在重复执行以下操作:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Wall -Wextra -Werror -pedantic" -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -pedantic"
Run Code Online (Sandbox Code Playgroud)
由于我不希望将这些标志嵌入到 CMakeLists 文件中(因为这种严格性只在 CI 中需要),因此我在 CI 中的配置命令上设置标志。
有没有办法以不需要重复标志的方式重写此命令?
注意:CMAKE_CPP_FLAGS不起作用。
在 C++20 中,我们有consteval声明立即函数的关键字。例如:
consteval int f(int x) { return x * x; }
Run Code Online (Sandbox Code Playgroud)
需要这样的函数来生成常量表达式。但是,根据标准,常量表达式不需要在编译时实际求值,除非它用在需要常量的地方,例如在模板参数中。例如,标准中似乎没有任何内容要求在编译时对其进行评估:
int a = f(10);
Run Code Online (Sandbox Code Playgroud)
然而,这些要求强烈表明立即函数应该在编译时进行评估。
标准中似乎也没有要求在编译时评估 constexpr 变量。所以即使我们创建变量constexpr,即
constexpr int a = f(10);
Run Code Online (Sandbox Code Playgroud)
它只断言这f(10)是一个常量表达式并生成a一个常量表达式(但同样,常量表达式不需要在编译时实际评估它们)。然而,就像以前一样,对 constexpr 变量的要求强烈表明它们应该在编译时进行评估。
只有constinit 变量的定义不同 - constinit 变量需要进行静态初始化,因此必须在编译时计算它们并直接嵌入到二进制文件中。然而,这个相关问题的答案说 constexpr 意味着 constinit,至少对于全局变量来说,这似乎与我上面写的内容相矛盾。
那么, consteval 函数和 constexpr 变量是否保证在编译时进行求值?
旁注:我的实际用例涉及尝试使用常量初始化结构中的字段,如下所示:
consteval int my_complicated_calculation() {
// do complicated mathematics and return an int
}
struct A {
int value;
A() : value{my_complicated_calculation()} {}
}
Run Code Online (Sandbox Code Playgroud) 考虑一下这段代码(从Simple-Web-Server中提取,但不需要知道库来回答这个问题):
HttpServer server;
thread server_thread;
server.config.port = 8080;
server.default_resource["GET"] = [](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
string content = "Hello world!"
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.size() << "\r\n\r\n" << content;
};
server_thread = thread([&server]() {
server.start();
});
Run Code Online (Sandbox Code Playgroud)
HttpServer::default_resource是一个std :: unordered_map,根据我的理解,它不是线程安全的. port是一张未签约的短片.
假设我的C++内存栅栏的理解是正确的,server通过新的线程中看到的,可能不是一个有效的状态为主线可能不会写的变化port,并default_resource从其他线程访问内存.因此,server.start()可能无法正常工作.
要解决这个问题,我必须通过添加到atomic_thread_fences 来更改代码:
HttpServer server;
thread server_thread;
server.config.port = 8080;
server.default_resource["GET"] = [](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
string content = "Hello world!"
*response …Run Code Online (Sandbox Code Playgroud) 使用右值引用时,可能会省略许多冗余副本,但这似乎要求我多次写入相同的函数(一个用于右值引用,一个用于const左值引用).但标准库似乎只需要声明一些函数.
例如:
#include <iostream>
#include <tuple>
void foo(int&& x){
x = 2;
}
int main()
{
int x = 1;
foo(x); // compile error
std::make_tuple(x); // ok
std::cout << x << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
调用foo(x)是一个编译错误,因为我无法隐式转换int为int&&.但我为什么std::make_tuple会工作感到困惑.该参考文献表明它只接受右值参考参数.当传入它的值是ravlue引用时,它似乎也不会复制,但是当我在上面的示例中使用它时,它会复制(正如大多数人所期望的那样).
我foo该怎么做这样的工作?
我正在编写一个由多个 s 组成的大型固定大小整数类型uint64_t,如下面的(简化的)示例所示。我希望我的类型表现得像内置整数类型,这意味着(除其他外):
然而,在我看来,人们无法编写一种同时满足这两个属性的类型。这是因为属性 1 要求类型是聚合,这意味着它必须没有构造函数,而我们需要一个构造函数来实现属性 2。
有没有办法编写一个满足这两个属性的大整数类型?
#include <array>
#include <cstdint>
struct uint128_t{
std::array<uint64_t, 2> data;
};
int main(){
uint128_t x; // uninitialized (good)
uint128_t y = 100; // can we make this work while ensuring that the previous line still works?
}
Run Code Online (Sandbox Code Playgroud) 我使用标准BinaryHeap作为算法的一部分,我需要检索最大的对象(通过一些最大的定义)。两个非等价元素可能都一样大(因此它们在二进制堆中的相对顺序无关紧要)——例如,我可能只对多字段结构的单个字段的排序感兴趣。
因此,让我的类型实现Ord和Eq. 相反,我可能应该实施PartialOrd和PartialEq唯一。但是,唉,BinaryHeap需要它的元素是Ord!为什么会这样,使用BinaryHeap这些类型的最惯用的方法是什么?
(顺便说一句,在 C++ 中,在这种情况下我会很容易地编写自定义比较器类型,并在比较器类型上模板化优先级队列。所以我不认为我想做的在数学上或算法上是错误的。)
我最近发现这段代码在GCC和MSVC中编译得很好:
auto foo = [](...){
cout << "foo() called" << endl;
};
Run Code Online (Sandbox Code Playgroud)
它接受任意数量的任何参数,并且对这些参数没有任何作用,因此它就好像auto被放置在...:
// All of these lines will call the lambda function
foo();
foo(100);
foo("Test");
foo("Testing", 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
关于lambda函数的C++参考似乎没有提到这一点,参数包上的页面也没有提及.
更令人惊讶的是,这无法编译:
auto foo = [](... x){ // compile error
cout << "foo() called" << endl;
};
Run Code Online (Sandbox Code Playgroud)
这种行为是否由标准规定,如果是这样,为什么前者编译而后者失败?