标签: c++20

Linux 包管理器将如何处理 C++20 模块?

现在是 2020 年,C++20 以及期待已久的 C++ 模块功能即将到来。但是在看了一些关于 CppCon 的演讲后,我发现 C++ 模块处于一个奇怪的地方,尤其是对于 Linux 包管理器(pacman、apt、emerge 等...)

据我所知,C++ 模块是

  1. 依赖编译器
    • 您不能在 Clang 中使用由 GCC 构建的模块
    • GCC 9.1 模块不适用于 GCC 9.2
  2. 您可以拥有同一模块的许多不同版本
    • 只要它们不导出到同一范围内
  3. 如果依赖项更新,您需要重建模块

我的问题是,在所有滚动发布发行版中,编译器一直在更新,用户可能有自己的编译器版本。目前可以只更新编译器或更新libstdc++. 但是对于模块,似乎建议libstdc++在编译器更新时必须更新。

当编译器更新时,包管理器将如何处理更新,例如 STL?我不认为为每个版本的编译器构建每个版本的 STL 模块是可行的。用户必须构建自己的 STL 模块也不是一个好主意。

c++ dependency-management package-management c++20 c++-modules

12
推荐指数
1
解决办法
1144
查看次数

什么可以防止类中相邻成员重叠?

考虑以下三个方面struct

class blub {
    int i;
    char c;

    blub(const blub&) {}
};

class blob {
    char s;

    blob(const blob&) {}
};

struct bla {
    blub b0;
    blob b1;
};
Run Code Online (Sandbox Code Playgroud)

int4 字节的典型平台上,大小、对齐方式和总填充1如下:

  struct   size   alignment   padding  
 -------- ------ ----------- --------- 
  blub        8           4         3  
  blob        1           1         0  
  bla        12           4         6  

Run Code Online (Sandbox Code Playgroud)

blubblob成员的存储之间没有重叠,即使大小 1blob原则上可以“适合” blub.

C++20 引入了no_unique_address属性,它允许相邻的空成员共享相同的地址。它还明确允许使用一个成员的填充来存储另一个成员的上述场景。来自cppreference(强调我的):

指示此数据成员不需要具有与其类的所有其他非静态数据成员不同的地址。这意味着如果成员有一个空类型(例如无状态分配器),编译器可能会优化它以不占用空间,就像它是一个空基一样。如果该成员不为空,则其中的任何尾部填充也可以重新用于存储其他数据成员。

事实上,如果我们在 上使用这个属性blub b0,大小会bla …

c++ language-lawyer c++20

12
推荐指数
1
解决办法
376
查看次数

如何在cmake项目中使用c++20

我想使用 c++20 中可用的头文件。

我正在使用最新版本的 cmake。

我的 CMakeFiles 看起来像

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_BUILD_TYPE debug)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
Run Code Online (Sandbox Code Playgroud)

我使用 clang 9 作为我的编译器。

但是,在包含以下内容时出现以下错误:

fatal error: 'format' file not found
#include <format>
Run Code Online (Sandbox Code Playgroud)

我也使用了标志-std=c++2a,但没有效果。简而言之,我觉得我在这里错过了一些重要的东西。我对 cmake 有点陌生,有什么帮助吗?

c++ format cmake c++20

12
推荐指数
1
解决办法
1万
查看次数

将奇异对齐的对象置于协程状态是否是定义的行为?

编辑:感谢大家的回答和回复。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 可能采用以下形式之一:

  1. 按照请求的大小传递传递给协程的所有参数,或者如果找不到这样的重载,
  2. 仅传递请求的大小。

无论调用采用哪种形式,请注意它不使用接受 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++ memory-alignment language-lawyer c++20 c++-coroutine

12
推荐指数
1
解决办法
334
查看次数

授予模板类专业化的构造函数/析构函数友好 - 在 C++17 下工作,但在 C++20 下失败

我发现了一种情况,代码在 C++17 下编译成功,但在 C++20 下编译失败。
这阻止了我们将现有的代码设计升级到更新的标准。
为什么这不能在 C++20 下编译?这似乎是对向后兼容性的奇怪破坏。

当我尝试为模板类专业化的构造函数/析构函数授予友好关系时会发生错误。

我正在使用带有 Ninja 的 MSVC 进行编译。
在 C++17 下编译成功。
在 C++20 下,我收到以下错误:

error C2838: '{ctor}': illegal qualified name in member declaration
error C2838: '{dtor}': illegal qualified name in member declaration
Run Code Online (Sandbox Code Playgroud)

这是在 C++20 下导致错误但在 C++17 下编译成功的代码的简化复制:

template<typename T, int V> class B {};

// specialization of class B
template<typename T> class B<T, 0> {
private:
    T _t;   // private data member
public:
    constexpr inline B(T* p, int i) noexcept;   // B constructor …
Run Code Online (Sandbox Code Playgroud)

c++ friend friend-function language-lawyer c++20

12
推荐指数
1
解决办法
373
查看次数

用 `&amp;&amp;` 和 `const` 限定符重载 operator== 导致 C++20 中的歧义

考虑struct S具有operator==相同&&限定符和不同const限定符的两个重载:

struct S {
  bool operator==(const S&) && { 
    return true;
  }
  bool operator==(const S&) const && { 
    return true;
  }
};
Run Code Online (Sandbox Code Playgroud)

如果我将两者Soperator==

S{} == S{};
Run Code Online (Sandbox Code Playgroud)

gcc 和 msvc 接受此代码,clang拒绝它:

<source>:14:7: error: use of overloaded operator '==' is ambiguous (with operand types 'S' and 'S')
  S{} == S{};
  ~~~ ^  ~~~
Run Code Online (Sandbox Code Playgroud)

为什么 clang 认为这里有一个不明确的重载决议?在这种情况下,非常量不应该是最好的候选人吗?

同样,如果我将两个S与合成的进行比较operator!=

S{} != S{};
Run Code Online (Sandbox Code Playgroud)

gcc 仍然接受此代码,但 msvc …

c++ comparison operator-overloading language-lawyer c++20

12
推荐指数
1
解决办法
290
查看次数

为什么 C++20 的要求表达式的行为不符合预期?

#include <type_traits>

template<typename T>
struct IsComplete final
    : std::bool_constant<requires{sizeof(T);}>
{};

int main()
{
    struct A;
    static_assert(!IsComplete<A>::value); // ok

    struct A{};
    static_assert(IsComplete<A>::value);  // error
}
Run Code Online (Sandbox Code Playgroud)

我预计第二个static_assert应该是真的,因为 A 现在是一个完整的类型。

为什么 C++20 的要求表达式的行为不符合预期?

c++ templates sfinae type-traits c++20

12
推荐指数
1
解决办法
745
查看次数

是否有必要在 std::coroutine_handle 上调用 destroy ?

std::coroutine_handle是C ++ 20的新协程的一个重要部分。例如,发电机经常(总是?)使用它。在我见过的所有示例中,在协程的析构函数中手动销毁句柄:

struct Generator {
    // Other stuff...
    std::coroutine_handle<promise_type> ch;

    ~Generator() {
        if (ch) ch.destroy();
    }
}
Run Code Online (Sandbox Code Playgroud)

这真的有必要吗?如果是的话,为什么没有这个已经被完成的coroutine_handle,是有一个RAII版本coroutine_handle,其行为这种方式,并会如果我们忽略了发生什么destroy电话?

例子:

  1. https://en.cppreference.com/w/cpp/coroutine/coroutine_handle(感谢 463035818_is_not_a_number
  2. C++20 标准也在 9.5.4.10 Example 2(在 N4892 上检查)中提到它。
  3. (德语)https://www.heise.de/developer/artikel/Ein-unendlicher-Datenstrom-dank-Coroutinen-in-C-20-5991142.html
  4. https://www.scs.stanford.edu/~dm/blog/c++-coroutines.html - 提到如果不调用它会泄漏,但没有引用标准中的段落或为什么不引用在 的析构函数中调用std::coroutine_handle

c++ coroutine c++20

12
推荐指数
1
解决办法
269
查看次数

如何定义任意 std::vector 满足的概念?

我想要一个concept需要任意向量作为返回类型:

template<typename T>
concept HasVector = requires (T t) {
    { T.vec() } -> std::same_as<std::vector<int>>; //works
    { T.vec() } -> std::same_as<std::vector<foo>>; //want to put something arbitrary in here
}
Run Code Online (Sandbox Code Playgroud)

这样我们就会有如下内容:

class A {
std::vector<int> vec() { /* ... */}
}

class B {
std::vector<double> vec() { /* ... */}
}

static_assert(HasVector<A>);
static_assert(HasVector<B>);
Run Code Online (Sandbox Code Playgroud)

此外,要求一个向量作为返回类型会更好,其值类型满足其他一些概念,即


template<typename T>
concept Arithmetic = // as in the standard

template<typename T>
concept HasArithmeticVector = requires (T t ) {
    { T. vec() } -> …
Run Code Online (Sandbox Code Playgroud)

c++ templates vector c++-concepts c++20

12
推荐指数
2
解决办法
1117
查看次数

使用函数作为回调时,有没有办法避免存储开销?

鉴于以下设置:

// ***** Library Code *****
#include <concepts>

template <std::invocable CbT>
struct delegated {
  explicit constexpr delegated(CbT cb) : cb_(std::move(cb)) {}

 private:
  [[no_unique_address]] CbT cb_;
};

// ***** User Code *****
#include <iostream>

namespace {
  inline constexpr void func() {}
}

struct MyFunc {
  constexpr void operator()() const {}
};


int main() {
    void (*func_ptr)() = func;

    auto from_func = delegated{func};
    auto from_func_ptr = delegated{func_ptr};
    auto from_lambda = delegated{[](){}};
    auto from_functor = delegated{MyFunc{}};

    std::cout << "func: " << sizeof(from_func) << …
Run Code Online (Sandbox Code Playgroud)

c++ c++20

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