该标准定义了几个“发生在之前”关系,这些关系将古老的“之前排序”扩展到多个线程:
\n\n\n
[intro.races]11 评估 A简单地发生在评估 B 之前,如果
\n(11.1) \xe2\x80\x94 A 在 B 之前排序,或者
\n
\n(11.2) \xe2\x80\x94 A 与 B 同步,或者
\n(11.3) \xe2\x80\x94 A 只是发生在 X 之前,并且X 只是发生在 B 之前。[注10:在没有消耗操作的情况下,发生在之前和简单发生在关系之前是相同的。\xe2\x80\x94 尾注]
\n12 评估 A强烈发生在评估 D 之前,如果:
\n(12.1) \xe2\x80\x94 A 在 D 之前排序,或者
\n(12.2) \xe2\x80\x94 A 与 D 同步,并且 A 和 D 都是顺序一致的原子操作\n([atomics.order] ),或
\n(12.3) \xe2\x80\x94 存在评估 B 和 C,使得 A 在 B 之前排序,B 仅发生在 C 之前,并且 C 在 D 之前排序,或者 …
适用于类的语法不适用于概念:
template <class Type>
concept C = requires(Type t) {
// ...
};
template <class Type>
concept C<Type*> = requires(Type t) {
// ...
};
Run Code Online (Sandbox Code Playgroud)
MSVC 对于“专业化”行的说法是:error C7606: 'C': concept cannot be explicitly instantiated, explicitly specialized or partially specialized。
为什么概念不能专门化?有理论上的原因吗?
我想测试一个类型是否可以传递给某个函数,但我想在函数查找上使用 ADL 并包含来自某个命名空间的函数。
考虑这段代码:
#include <utility>
#include <vector>
template<class T>
concept Swappable = requires(T& a, T& b)
{
swap(a,b);
};
static_assert(Swappable<std::vector<int>>); // #1
static_assert(Swappable<int>); // #2
Run Code Online (Sandbox Code Playgroud)
#1 成功,它发现std::swapbecausestd是 的关联命名空间std::vector<int>。但 #2 失败了,内置类型没有关联的命名空间。
我该怎么写这样的东西:
template<class T>
concept Swappable = requires(T& a, T& b)
{
using std::swap; // illegal
swap(a,b);
};
Run Code Online (Sandbox Code Playgroud)
AFAIK,您不允许在 require 表达式中使用 using 声明。
(注意,虽然对此有一个完美的标准 C++ 概念,但std::swappable此示例swap仅用于说明。我并不是特别想测试某些东西是否实际上是可交换的,我只是想找到一种方法来实现这样的概念其中自定义函数在已知命名空间中具有默认实现,但可能在关联的命名空间中具有重载。)
编辑作为一种解决方法,我可以在一个单独的名称空间中实现这个概念,其中的名称被拉入。对此不太满意,但它有效。
namespace detail
{
using std::swap;
template<class T>
concept Swappable = …Run Code Online (Sandbox Code Playgroud) C ++ 11给我们带来了UTF-8字面量的u8前缀,几年前我认为这很酷,并在代码中添加了以下内容:
std::string myString = u8"?";
Run Code Online (Sandbox Code Playgroud)
一切都很好,但是在C ++ 20中出现了问题,因为u8创建了char8_t *,并且与仅使用char的std :: string不兼容,因此似乎不再可以编译了。
我应该创建一个新的utf8string吗?在C ++ 20世界中,如果我们有更显式的类型与标准std :: string完全不匹配,那么一致的正确方法是什么?
constinit是P1143中提出的C ++ 20中的新关键字和说明符。
标准中提供了以下示例:
const char * g() { return "dynamic initialization"; }
constexpr const char * f(bool p) { return p ? "constant initializer" : g(); }
constinit const char * c = f(true); // OK
constinit const char * d = f(false); // ill-formed
Run Code Online (Sandbox Code Playgroud)
我想到了几个问题:
什么constinit意思 为什么要引入?在什么情况下我们应该使用它?
它使变量不可变吗?是暗示const还是constexpr?
变量可以是const和constinit吗?怎么样constexpr和constinit?
可以将说明符应用于哪些变量?为什么我们不能将其应用于static非thread_local变量?
有性能优势吗?
该问题旨在作为 …
鉴于:
#include <concepts>
#include <iostream>
template<class T>
struct wrapper;
template<std::signed_integral T>
struct wrapper<T>
{
wrapper() = default;
void print()
{
std::cout << "signed_integral" << std::endl;
}
};
template<std::integral T>
struct wrapper<T>
{
wrapper() = default;
void print()
{
std::cout << "integral" << std::endl;
}
};
int main()
{
wrapper<int> w;
w.print(); // Output : signed_integral
return 0;
}
Run Code Online (Sandbox Code Playgroud)
从上面的代码中,int符合std::integral和std::signed_integral概念。
令人惊讶的是,这会在 GCC 和 MSVC 编译器上编译并打印“signed_integral”。我原以为它会失败,并出现“模板专业化已经定义”的错误。
好的,这是合法的,足够公平,但为什么std::signed_integral选择而不是std::integral?当多个概念符合模板参数的条件时,标准中是否定义了任何规则来选择模板特化?
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 char从unsigned char具有不确定值的左值初始化变量(导致使用不确定值初始化)。
这本身并不会因此导致不确定的行为,但会为其他类型T不属于无符号窄字符类型或std::byte如int x = x;。这些注意事项也适用于 C++17 及之前的版本,另请参阅底部的链接问题。
然而,即使对于unsigned char x = x;,当前草案的[basic.lifetime]/7说:
类似地,在对象的生命周期开始之前 [...] 使用不依赖于其值的泛左值的属性是明确定义的。在以下情况下,程序具有未定义的行为:
泛左值用于访问对象,或
[...]
这似乎意味着x示例中的that值只能在其生命周期内使用。
[...]
类型 T 的对象的生命周期在以下情况下开始:
- [...] 和
- 它的初始化(如果有)完成(包括空初始化)([dcl.init]),
[...]
因此x的生命周期仅在初始化完成后才开始。但是在引用的例子中 …
C++20 引入了显式 (bool),它在编译时有条件地选择构造函数是否显式。
下面是我在这里找到的一个例子。
struct foo {
// Specify non-integral types (strings, floats, etc.) require explicit construction.
template <typename T>
explicit(!std::is_integral_v<T>) foo(T) {}
};
foo a = 123; // OK
foo b = "123"; // ERROR: explicit constructor is not a candidate (explicit specifier evaluates to true)
foo c {"123"}; // OK
Run Code Online (Sandbox Code Playgroud)
谁能告诉我explicit (bool)除了 using 之外的任何其他用例std::is_integral?
我已经看到 IDE 中的默认标准通常不是最新发布的标准,甚至不是 IDE 中的最新标准。例如 JetBrains 的 Clion 有 C++20 和 C++17,但默认选项是 C++14。
是否有理由不使用最新发布的标准?
考虑这个代码:
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++ ×10
c++20 ×10
c++-concepts ×4
c++14 ×1
concurrency ×1
constinit ×1
explicit ×1
lifetime ×1
standards ×1
stdstring ×1