标签: c++20

在自己的初始化程序中使用变量

C++20 标准草案的[basic.scope.pdecl]/1在注释中包含以下(非规范性)示例(合并拉取请求 3580之前的部分引用,请参阅此问题的答案):

unsigned char x = x;
Run Code Online (Sandbox Code Playgroud)

[...] x 用它自己的(不确定的)值初始化。

这实际上在 C++20 中有明确定义的行为吗?


通常T x = x;,由于x的值在初始化完成之前是不确定的,因此表单的自初始化具有未定义的行为。评估不确定的值通常会导致未定义的行为([basic.indent]/2),但在[basic.indent]/2.3中有一个特定的例外,它允许直接unsigned charunsigned char具有不确定值的左值初始化变量(导致使用不确定值初始化)。

这本身并不会因此导致不确定的行为,但会为其他类型T不属于无符号窄字符类型或std::byteint x = x;。这些注意事项也适用于 C++17 及之前的版本,另请参阅底部的链接问题。

然而,即使对于unsigned char x = x;,当前草案的[basic.lifetime]/7说:

类似地,在对象的生命周期开始之前 [...] 使用不依赖于其值的泛左值的属性是明确定义的。在以下情况下,程序具有未定义的行为:

  • 泛左值用于访问对象,或

  • [...]

这似乎意味着x示例中的that值只能在其生命周期内使用。

[basic.lifetime]/1说:

[...]

类型 T 的对象的生命周期在以下情况下开始:

  • [...] 和
  • 它的初始化(如果有)完成(包括空初始化)([dcl.init]),

[...]

因此x的生命周期仅在初始化完成后才开始。但是在引用的例子中 …

c++ initialization lifetime language-lawyer c++20

23
推荐指数
1
解决办法
637
查看次数

是否有理由不使用最新的 C++ 标准?

我已经看到 IDE 中的默认标准通常不是最新发布的标准,甚至不是 IDE 中的最新标准。例如 JetBrains 的 Clion 有 C++20 和 C++17,但默认选项是 C++14。

是否有理由不使用最新发布的标准?

c++ standards c++14 c++20

23
推荐指数
1
解决办法
1797
查看次数

为什么我不能在类范围内声明一个概念?

考虑这个代码:

struct A
{
    template <typename T>
    concept foo = true;
};
Run Code Online (Sandbox Code Playgroud)

它不编译。我的 Clang 10 给了我error: concept declarations may only appear in global or namespace scope,GCC 说了类似的话。

有理由不允许吗?我不明白为什么它不能工作,即使封闭类是一个模板。

c++ c++-concepts c++20

23
推荐指数
1
解决办法
1061
查看次数

为什么在概念中使用std :: forward?

我正在阅读Constraints上cppreference页面并注意到这个例子:

// example constraint from the standard library (ranges TS)
template <class T, class U = T>
concept bool Swappable = requires(T t, U u) {
    swap(std::forward<T>(t), std::forward<U>(u));
    swap(std::forward<U>(u), std::forward<T>(t));
};
Run Code Online (Sandbox Code Playgroud)

我很困惑他们为什么要用std::forward.有些人试图在模板参数中支持引用类型吗?我们不想swapforward左值调用,并且当标量(非参考)类型时T,表达式不是rvalues U吗?

例如,我希望这个程序在Swappable实现时失败:

#include <utility>

// example constraint from the standard library (ranges TS)
template <class T, class U = T>
concept bool Swappable = requires(T t, U u) {
    swap(std::forward<T>(t), std::forward<U>(u));
    swap(std::forward<U>(u), std::forward<T>(t)); …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts c++20

22
推荐指数
1
解决办法
484
查看次数

C++20 比较:关于不明确的反向运算符的警告

考虑这个有效的 C++17 示例:

struct A {
   bool operator==(const A&);
};


int main() {
   return A{} == A{};
}
Run Code Online (Sandbox Code Playgroud)

使用 -std=c++20 在 clang 中编译时,它给出

struct A {
   bool operator==(const A&);
};


int main() {
   return A{} == A{};
}
Run Code Online (Sandbox Code Playgroud)

这个警告是否意味着 C++20 不允许使用典型的比较运算符来比较两个相同类型的对象?什么是正确的选择?这种情况在未来的选秀中会发生变化吗?

c++ c++20

22
推荐指数
2
解决办法
2723
查看次数

contiguous_range 总是一个 sized_range 吗?

我有以下关于 C++20 中的 range 库的问题:

std::ranges::contiguous_range<T>一个任意类型T.

我可以假设std::ranges::sized_range<T>吗?

c++ iterator stl language-lawyer c++20

22
推荐指数
3
解决办法
824
查看次数

为什么不能使用 static_cast 将数组类型的纯右值转换为相同类型?

#include <iostream>
int main(){
    using type = int[2];
    static_cast<type>(type{1,2});  //#1
}
Run Code Online (Sandbox Code Playgroud)

锵和GCC都抱怨#1是形成不良的,并给予怪异的诊断。

Clang 报告

static_cast from 'int *' to 'type' (aka 'int [2]') is not allowed  
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会报告

invalid 'static_cast' from type 'type' {aka 'int [2]'} to type 'type' {aka 'int [2]'}   
Run Code Online (Sandbox Code Playgroud)

但是,根据expr.static.cast#4

如果存在从 E 到 T的隐式转换序列([over.best.ics]),则表达式 E 可以显式转换为类型T

把一个类型转换成同一个类型不就叫恒等转换吗?
over.best.ics#general-8

如果不需要转换来将参数与参数类型匹配,则隐式转换序列是由身份转换 ([over.ics.scs]) 组成的标准转换序列。

我认为这里的一个关键规则是

转换序列是 [conv] 中定义的隐式转换,这意味着它受对象的初始化规则或单个表达式([dcl.init]、[dcl.init.ref])的引用的控制。

这意味着,假设一个结果对象将由t纯右值初始化。

static_cast from 'int *' to 'type' (aka 'int [2]') is not …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++20

22
推荐指数
1
解决办法
426
查看次数

只有布尔文字值的概念是格式错误的,不需要诊断吗?

我在完全从任何模板中删除的上下文中玩弄 C++ 概念和函数重载,并偶然发现了这一点:

struct S
{
    int mult(int x) requires (true)  { return x; }
    int mult(int x) requires (false) { return x * 2; }
};

int main()
{
    std::cout << S{}.mult(5) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

g++ 11 拒绝编译此代码段,因为requires-clauses 可能不会附加到非模板函数。

然而,clang++ 13 对这个代码段很好,但令人惊讶的是它吐出10而不是5我所期望的。

我知道 C++20 标准最近才出炉,所以我完全理解关于概念有很多问题需要解决。

忽略常量字面概念的明显无用,我的问题是:带有 -requires子句的程序是否总是格式错误的false,可能不需要诊断?或者,也许,正如 g++ 所说,我什至根本没有合法的 C++?

c++ language-lawyer c++-concepts c++20

22
推荐指数
2
解决办法
923
查看次数

分支似然提示是否通过函数调用进行?

我遇到过一些场景,我想说函数的返回值可能在函数体内,而不是调用它的 if 语句。

例如,假设我想将代码从使用LIKELY宏移植到使用新[[likely]]注释。但这些在句法上不同的地方:

#define LIKELY(...) __builtin_expect(!!(__VA_ARGS__),0)
if(LIKELY(x)) { ... } 
Run Code Online (Sandbox Code Playgroud)

对比

if(x) [[likely]] { ... }
Run Code Online (Sandbox Code Playgroud)

没有简单的方法可以重新定义LIKELY宏以使用注释。会定义一个函数

inline bool likely(bool x) { 
  if(x) [[likely]] return true;
  else return false;
}
Run Code Online (Sandbox Code Playgroud)

将提示传播到if?像

if(likely(x)) { ... }
Run Code Online (Sandbox Code Playgroud)

类似地,在通用代码中,很难在实际if语句中直接表达算法似然信息,即使该信息在其他地方是已知的。例如,a copy_ifwhere 谓词几乎总是假的。据我所知,没有办法用属性来表达,但如果分支权重信息可以通过函数传播,这是一个已解决的问题。

到目前为止,我还没有找到关于这个的文档,我不知道通过查看输出的程序集来测试这个的好设置。

c++ compiler-optimization branch-prediction c++20

21
推荐指数
2
解决办法
770
查看次数

C++20 协程,await_resume、return_value 和 yield_value 的意外重新排序

背景

我有个任务类型既可以co_returnco_yield。在 LLVM 中,任务按预期工作并通过了一些早期测试。在 MSVC 和 GCC 中,代码以相同的方式失败(巧合?)。


简要问题

具有以下测试功能:

Task<int> test_yielding()
{
    co_yield 1;
    co_return 2;
}
Run Code Online (Sandbox Code Playgroud)

从 Task 对象中检索了两个值。

auto a = co_await fn;
auto b = co_await fn;
Run Code Online (Sandbox Code Playgroud)

a 的值预期为 1,b 的值预期为 2。

结果针对 进行测试a + b == 3

上面的测试通过了,但是下面的测试失败了:

auto res = co_await fn + co_await fn
Run Code Online (Sandbox Code Playgroud)

GCC 和 MSVC 的 res 值为 4。两者都是从最终的 co_return 中检索到的。据我了解,第一次和第二次调用的co_await fn顺序应该是 1 和 2。

在 MSVC 和 GCC 中,代码失败,因为它们似乎重新排序await_resumereturn_value …

c++ c++20 c++-coroutine

21
推荐指数
1
解决办法
642
查看次数