标签: c++20

为什么C++ 11具有值参数的隐式移动,而不是rvalue参数?

在C++ 11中,值参数(和其他值)在返回时享受隐式移动:

A func(A a) {
    return a; // uses A::A(A&&) if it exists
}
Run Code Online (Sandbox Code Playgroud)

至少在MSVC 2010中,右值参考参数需要std::move:

A func(A && a) {
    return a; // uses A::A(A const&) even if A::A(A&&) exists
}
Run Code Online (Sandbox Code Playgroud)

我认为内部函数,右值引用和值的行为类似,唯一的区别是在值的情况下,函数本身负责销毁,而对于右值引用,责任在外面.

在标准中对待它们的动机是什么?

c++ rvalue-reference move-semantics c++11 c++20

21
推荐指数
3
解决办法
3688
查看次数

我们在GCC 9中有C ++ 20范围库吗?

新发布的GCC 9是否支持C ++ 20范围库?

我从以下位置复制了范围库的示例代码:https : //en.cppreference.com/w/cpp/ranges

#include <vector>
#include <ranges>
#include <iostream>

int main()
{
  std::vector<int> ints{0,1,2,3,4,5};
  auto even = [](int i){ return 0 == i % 2; };
  auto square = [](int i) { return i * i; };

  for (int i : ints | std::view::filter(even) | std::view::transform(square)) {
    std::cout << i << ' ';
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,当使用g ++ 9.1(Ubuntu 18.04 LTS(Bionic Beaver))进行编译时,它抱怨<ranges>找不到:

$ g++ -std=c++2a cpp2a.cpp 
cpp2a.cpp:2:10: fatal error: ranges: No such file or …
Run Code Online (Sandbox Code Playgroud)

c++ gcc c++20

21
推荐指数
4
解决办法
2523
查看次数

如果显式默认或删除了构造函数,为什么自C ++ 20起聚合初始化不再起作用?

我正在将C ++ Visual Studio项目从VS2017迁移到VS2019。

我现在遇到一个错误,以前没有发生过,可以通过以下几行代码来重现:

struct Foo
{
    Foo() = default;
    int bar;
};
auto test = Foo { 0 };
Run Code Online (Sandbox Code Playgroud)

错误是

(6):错误C2440:“正在初始化”:无法从“初始化列表”转换为“ Foo”

(6):注意:没有构造函数可以采用源类型,或者构造函数重载解析度不明确

该项目用/std:c++latest标志编译。我把它复制在了哥德螺栓上。如果我将其切换到/std:c++17,它可以像以前一样正常编译。

我试图用clang编译相同的代码,-std=c++2a并得到了类似的错误。同样,默认或删除其他构造函数也会产生此错误。

显然,VS2019中添加了一些新的C ++ 20功能,我假设在https://en.cppreference.com/w/cpp/language/aggregate_initialization中描述了此问题的起源。在那里,它表示一个聚合可以是(除其他条件外)具有的结构

  • 没有用户提供的,继承的或显式的构造函数(允许使用显式默认或删除的构造函数)(自C ++ 17起)(直到C ++ 20)
  • 没有用户声明或继承的构造函数(自C ++ 20起)

请注意,括号中的部分“明确允许使用默认或删除的构造函数”已删除,并且“用户提供”更改为“用户声明”。

因此,我的第一个问题是,我是否假设标准的这种更改是我的代码以前编译但现在不再编译的原因?

当然,解决此问题很容易:只需删除显式默认的构造函数即可。

但是,我已经在所有项目中明确地默认并删除了很多构造函数,因为我发现以这种方式使代码更具表现力是一个好习惯,因为与隐式默认或删除的构造函数相比,这样做只会带来更少的惊喜。但是,通过这种更改,这似乎不再是一个好习惯了...

所以我的实际问题是: 从C ++ 17到C ++ 20的变化背后的原因什么?向后兼容的突破是故意的吗?是否有一些折衷办法,例如“确定,我们在这里破坏了向后兼容性,但这是为了更大的利益。”吗?这个更大的好处是什么?

c++ backwards-compatibility c++17 c++20

21
推荐指数
3
解决办法
1022
查看次数

如何通过自定义错误消息使概念失败 (C++20)

概念非常擅长将错误定位到“不满足约束”的代码行。

但是,我想知道是否可以在那里发布自定义信息消息。static_assert 的好处就是这种可能性。用例:任何想要帮助用户找出某个表达式不满足约束的原因的库。

这是一个简单的例子,只是为了有一些代码。您可能会争辩说,任何体面的“用户”都必须能够弄清楚编译器的注释“因为 'is_base_of<Base, C>' 评估为 false”,但更多的自定义信息不会受到伤害。肯定会有更复杂的概念。


template<typename B, typename D> 
concept is_base_of = std::is_base_of_v<B, D>;

template <typename T, is_base_of<T> BaseType>
struct BaseWrapper { };  

int main() 
{
    class Base {};
    class Derived : public Base {};
    class C {};

    using T1 = BaseWrapper<Derived,Base>;
    using T2 = BaseWrapper<C,Base>;         // fails right here, but a custom message would be nice
}

Run Code Online (Sandbox Code Playgroud)

c++ templates compiler-errors c++-concepts c++20

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

标记可能导致构造返回对象异常的函数 `noexcept`

考虑这个函数:

std::vector<unsigned> copy(std::vector<unsigned> const& v) noexcept
{ return v; }

int main()
{
   try {
       (void)copy({1, 2, 3});
   } catch(...) {}
}

Run Code Online (Sandbox Code Playgroud)

返回对象的副本构造可能会抛出。在这种情况下,异常是否会传播给调用者(即它被认为发生在main),从而在处理catch(...)程序中进行处理?或者异常会遇到noexcept并导致调用std::terminate()

C++17/C++20 中关于生命周期规则的变化(标准化 RVO、临时物化、隐式对象创建等)是否相对于标准的先前版本改变了这方面的一些规则?

c++ exception language-lawyer c++17 c++20

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

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

我遇到过一些场景,我想说函数的返回值可能在函数体内,而不是调用它的 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
查看次数

在 C++20 中使用 lambda 进行参数包扩展

案例一

考虑 lambdanoexcept说明符中的以下包扩展:

template <bool... B> 
auto g() {  
  ([]() noexcept(B) {}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

Clang 和 MSVC 接受此代码,但 GCC拒绝

error: expansion pattern '<lambda>' contains no parameter packs
Run Code Online (Sandbox Code Playgroud)

这是一个有效的代码吗?我应该信任哪个编译器?它看起来像是与PR 47226相关的旧 GCC 错误。

案例2

考虑 lambda 中的以下包扩展requires-clause

template <bool... B> 
auto g() {  
  ([](auto) requires(B) {}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Clang 和 MSVC 仍然接受此代码,而 GCC以相同的错误消息拒绝它。这只是同一个错误吗?

案例3

考虑 lambda 模板列表中的以下包扩展:

template <typename... Args> 
void g(Args...) {
  ([]<Args>(){}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

这次三个编译器拒绝了相同的错误信息: …

c++ lambda language-lawyer variadic-templates c++20

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

std::construct_at 是否使联合的数组成员处于活动状态?

看这个例子(godbolt):

#include <memory>

union U {
    int i[1];
};

constexpr int foo() {
    U u;
    std::construct_at(u.i, 1);
    return u.i[0];
}

constexpr int f = foo();
Run Code Online (Sandbox Code Playgroud)

gcc 和 msvc 成功编译了这个,但 clang 抱怨:

常量表达式中不允许构造没有活动成员的联合体成员“i”的子对象

哪个编译器是正确的?我认为 clang 在这里是错误的,因为 C++20 隐式创建对象(P0593)应该使该程序有效(因为应该隐式创建数组,这应该处于u.i活动状态),但我不确定。

c++ language-lawyer c++20

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

由于整数是内置类型,因此整数类类型在 C++ 中意味着什么

在阅读文档时,std::numeric_limits我发现了以下声明

还提供了所有整数类类型的特化。(自 C++20 起)

我的问题是上面的语句中整数类类型是什么意思。我的意思是,我知道这int是 C++ 中的内置类型。我们可以在C++中提供用户定义的类。但我从未读过有关整数类类型的内容。我尝试在谷歌上搜索该短语,但没有找到与此相关的任何内容。

c++ types c++20

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