考虑以下简单的协程,它跟踪其构建和销毁:
#include <coroutine>
#include <iostream>
struct simple {
static inline int x = 0;
int id = 0;
simple() : id{ x++ } { std::cout << id << " constructed\n"; }
simple(simple&&) : id{ x++ } { std::cout << id << " move constructed\n"; }
~simple() { std::cout << id << " destructed\n"; }
struct promise_type {
simple get_return_object() { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
auto initial_suspend() noexcept { return std::suspend_never{}; }
auto final_suspend() …
Run Code Online (Sandbox Code Playgroud) 我正在浏览“原子操作库”,并遇到了原子“等待”和“notify_ ”方法的新 C++20 功能。我很好奇 std::condition_variable 的 'wait' 和 'notify_ ' 方法有何不同。
编辑:感谢大家的回答和回复。Language Lawyer 的答案在技术上是正确的,因此被接受,但 Human-Compiler 的答案是唯一符合赏金标准(获得 2+ 分)的答案,或者对问题的特定主题进行了充分阐述。
将对象b
置于协程状态是否定义了行为(例如,将其作为参数,或将其保留在暂停点上),在哪里alignof(b) > __STDCPP_DEFAULT_NEW_ALIGNMENT__
?
例子:
inline constexpr size_t large_alignment =
__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2;
struct alignas(large_alignment) behemoth {
void attack();
unsigned char data[large_alignment];
};
task<void> invade(task_queue &q) {
behemoth b{};
co_await submit_to(q);
b.attack();
}
Run Code Online (Sandbox Code Playgroud)
当调用协程时,协程状态的堆内存通过operator new
.
此调用operator new
可能采用以下形式之一:
无论调用采用哪种形式,请注意它不使用接受 a 的重载std::align_val_t
,这是分配必须对齐多于 的内存所必需的__STDCPP_DEFAULT_NEW_ALIGNMENT__
。因此,如果__STDCPP_DEFAULT_NEW_ALIGNMENT__
必须将对齐大于 的对象保存在协程状态中,则应该无法保证该对象最终会在内存中正确对齐。
async f(): Assertion `reinterpret_cast<uintptr_t>(&b) % 32ull == 0' failed.
Run Code Online (Sandbox Code Playgroud)
所以它绝对不能在 GCC …
在 C++20 中,<algorithm>
头文件获得了两种新算法:shift_left()
和shift_right()
. 它们都接受任何 LegacyForwardIterator。对于shift_left()
,指定“以i
从?0
”开始的递增顺序执行移动;对于shift_right()
,指定“如果ForwardIt
满足 LegacyBidirectionalIterator 要求,则按照从i
开始的递减顺序执行移动last - first - n - 1
”。
我可以想到一个相当简单的实现方法shift_left()
:
template <typename ForwardIt>
constexpr inline ForwardIt shift_left(ForwardIt first, ForwardIt last, typename std::iterator_traits<ForwardIt>::difference_type n) {
if (n <= 0) return last;
ForwardIt it = first;
for (; n > 0; --n, ++it) {
if (it == last) return first;
}
return std::move(it, last, first);
} …
Run Code Online (Sandbox Code Playgroud) 由于P0593 为低级对象操作隐式创建对象已被接受,因此现在可以在 C++20 中隐式创建对象。
具体而言,提案中引入的措辞允许某些操作(例如std::malloc
)自动创建和启动某些类型的对象的生命周期,即所谓的隐式生命周期类型,如果此类对象的引入会导致具有其他未定义行为的程序具有定义的行为。见[intro.object]/10。
该草案现在进一步指出,如果可以隐式创建多个此类对象集以提供程序定义的行为,则未指定创建这些对象中的哪一个。(相关句子似乎没有出现在我可以访问的最后一个提案修订版中,R5,但在提交草案中。)
实际上是否有一个程序可以观察到这种隐式创建的对象集的选择?换句话说,是否有一个程序通过这个新规则定义了但未指定的行为,以便可以从输出推断出哪些类型的隐式对象(从多个可能的对象中)被创建?
还是这句话只是为了澄清抽象机器上的程序执行(没有可观察到的影响)?
这个问题是指在最新的C++20草案中增加了P0593。
这是我的例子:
#include <cstdlib>
#include <cstdio>
void foo(void *p)
{
if ( std::getchar() == 'i' )
{
*(int *)p = 2;
std::printf("%d\n", *(int *)p);
}
else
{
*(float *)p = 2;
std::printf("%f\n", *(float *)p);
}
}
int main()
{
void *a = std::malloc( sizeof(int) + sizeof(float) );
if ( !a ) return EXIT_FAILURE;
foo(a);
// foo(a); [2]
}
Run Code Online (Sandbox Code Playgroud)
此代码是否针对最新草案下的所有输入进行了明确定义?
P0593 中表达的基本原理非常清楚[2]
,如果两个用户输入项不同,取消注释将导致由于严格的别名违规而导致未定义的行为。隐式对象创建应该只发生一次,在malloc
; 它不是由foo
.
对于程序的任何实际运行,都存在一个未指定的隐式对象集的成员,可以使程序定义良好。但是我不清楚 [intro.object]/10 中提到的隐式对象创建的选择是否必须在malloc
发生时进行;或者决定是否可以“时间旅行”。
对于将二进制 blob 读入缓冲区然后做出如何访问它的运行时决定(例如反序列化;并且标头告诉我们是浮点数还是整数即将出现)的程序,可能会出现同样的问题。
为了在 C++20 中使用自编模块提出问题或演示错误/功能,能够使用Matt Godbolt 的编译器资源管理器会很棒。
例子:
test.cpp(模块测试):
export module test;
export template<typename T>
void do_something(const T&)
{
}
Run Code Online (Sandbox Code Playgroud)
编译 clang++ -std=c++20 -stdlib=libc++ -fmodules -c -Xclang -emit-module-interface -o test.pcm test.cpp
主.cpp:
import test;
int main() {
do_something(7);
}
Run Code Online (Sandbox Code Playgroud)
编译 clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-modules -fimplicit-module-maps -fprebuilt-module-path=. main.cpp
问:有没有办法用编译器资源管理器来做到这一点?
我在浏览cppreference 时看到vector
C++20 中删除了它的比较操作,并<=>
引入了飞船运算符 ( )。对于许多其他标准库容器,如set
和 ,可以看到同样的事情map
。
如何在新标准中进行比较?另外,C++20 会开始在旧代码上出错吗?
在一个相关的问题(“ std::string 格式,如 sprintf ”)中,我了解了这个很棒的新 C++20 标头<format>。
但是,似乎没有支持 compiler。这是正确的还是有办法使用它?
我正在使用带有-std=c++2a
标志的g++ 9.3,但<format>
无法识别库。
#include <format> // fatal error: format: No such file or directory
#include <iostream>
int main(){
std::cout << std::format("Hello {}!", "World");
}
Run Code Online (Sandbox Code Playgroud)
g++-9 test.cpp -o test -std=c++2a
我想摆脱enable_if
模板中的所有邪恶s 并用 C++20 概念替换它们,但是几乎没有关于概念的任何信息,并且几乎我阅读的任何来源的语法都发生了变化。
这是一个函数,它接受任何带有MyClass
值的容器的两个迭代器:
template <class IteratorType, typename = std::enable_if<std::is_same<
typename std::iterator_traits<IteratorType>::value_type,
MyClass
>::value, void>>
void myFunction( IteratorType begin, IteratorType end ) {}
Run Code Online (Sandbox Code Playgroud)
我知道可以使用概念转换此功能,但我找不到好的线索开始。
c++ ×10
c++20 ×10
algorithm ×1
c++-concepts ×1
c++-modules ×1
enable-if ×1
formatting ×1
g++ ×1
gcc ×1
header-files ×1
sfinae ×1
stdatomic ×1