现在是 2020 年,C++20 以及期待已久的 C++ 模块功能即将到来。但是在看了一些关于 CppCon 的演讲后,我发现 C++ 模块处于一个奇怪的地方,尤其是对于 Linux 包管理器(pacman、apt、emerge 等...)
据我所知,C++ 模块是
我的问题是,在所有滚动发布发行版中,编译器一直在更新,用户可能有自己的编译器版本。目前可以只更新编译器或更新libstdc++
. 但是对于模块,似乎建议libstdc++
在编译器更新时必须更新。
当编译器更新时,包管理器将如何处理更新,例如 STL?我不认为为每个版本的编译器构建每个版本的 STL 模块是可行的。用户必须构建自己的 STL 模块也不是一个好主意。
c++ dependency-management package-management c++20 c++-modules
考虑以下三个方面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)
在int
4 字节的典型平台上,大小、对齐方式和总填充1如下:
struct size alignment padding
-------- ------ ----------- ---------
blub 8 4 3
blob 1 1 0
bla 12 4 6
Run Code Online (Sandbox Code Playgroud)
blub
和blob
成员的存储之间没有重叠,即使大小 1blob
原则上可以“适合” blub
.
C++20 引入了no_unique_address
属性,它允许相邻的空成员共享相同的地址。它还明确允许使用一个成员的填充来存储另一个成员的上述场景。来自cppreference(强调我的):
指示此数据成员不需要具有与其类的所有其他非静态数据成员不同的地址。这意味着如果成员有一个空类型(例如无状态分配器),编译器可能会优化它以不占用空间,就像它是一个空基一样。如果该成员不为空,则其中的任何尾部填充也可以重新用于存储其他数据成员。
事实上,如果我们在 上使用这个属性blub b0
,大小会bla …
我想使用 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 有点陌生,有什么帮助吗?
编辑:感谢大家的回答和回复。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++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) 考虑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)
如果我将两者S
与operator==
:
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 …
#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 的要求表达式的行为不符合预期?
的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
电话?
例子:
std::coroutine_handle
。我想要一个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) 鉴于以下设置:
// ***** 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++ ×10
c++20 ×10
templates ×2
c++-concepts ×1
c++-modules ×1
cmake ×1
comparison ×1
coroutine ×1
format ×1
friend ×1
sfinae ×1
type-traits ×1
vector ×1