C ++ 20引入std::common_reference。目的是什么?有人可以举一个使用它的例子吗?
This is a follow-up of this SO Answer. Given a flat input range and three size_t dimensions, the code creates a nested random_access_range of random_access_ranges of random_access_ranges, modelling a three-dimensional array.
Iterating over the elements in the "multidimensional" range using a nested-for loop and indices is a bit slower than directly iterating over the elements of the input range (factor 4 slower). I suppose some performance drop can be expected, but a factor of 4 hurts …
在C++ 20中,__VA_OPT__如果参数的数量大于零,则预处理器支持作为可选地扩展可变参数宏中的标记的方法.(这消除了对##__VA_ARGS__GCC扩展的需求,这是一个不可移植且丑陋的黑客.)
Clang SVN已实现此功能,但尚未为其添加功能测试宏.任何聪明的预处理器黑客能否找到一种方法来检测__VA_OPT__支持的存在与否,而不会导致硬错误或可移植性警告?
来自cppreference.com的报价:
添加模板特化
允许为任何标准库类添加模板特化(从C++ 20开始)| 模板到命名空间std只有当声明依赖于至少一个程序定义的类型并且特化满足原始模板的所有要求时,除非禁止这样的特化.
是否意味着,从C++ 20开始,将std不再允许将函数模板的特化添加到用户定义类型的命名空间中?如果是这样,它意味着许多现有代码可能会破坏,不是吗?(在我看来,这是一种"激进"的改变.)此外,它会向这些代码注入未定义的行为,这不会触发编译错误(警告有希望).
C++20 允许使用auto函数参数类型。
它是否还允许auto用作函数参数类型的模板参数占位符(不相似,但在某种程度上符合C++17 template<auto>的精神)?
所以下面的代码,在 C++20 之前:
template<typename First, typename Second>
void printPair(const std::pair<First, Second>& p) {
std::cout << p.first << ", " << p.second;
}
Run Code Online (Sandbox Code Playgroud)
可以写成:
void printPair(const std::pair<auto, auto>& p) {
std::cout << p.first << ", " << p.second;
}
Run Code Online (Sandbox Code Playgroud)
它确实可以编译并与概念的实验性 GCC 实现一起很好地工作。
它是 C++20 的合法语法吗?
C++11 引入了一种新的内存模型,让“运行”C++11 代码的抽象机器有关于多线程的概念。它还引入了一组内存顺序,内存加载/存储操作遵循这些顺序。
C++20 的维基百科页面说它有
修改后的内存模型。
它给出的参考资料说 C++11 的内存模型有许多缺陷,C++20 将对其进行修改。
有人可以举例说明 C++11 的内存模型带来的问题,以及 C++20 中的问题如何解决吗?
相关问题: C++11的内存模型介绍
为什么聚合推导中不支持大括号初始化列表但支持大括号省略?
#include <iostream>
template<typename T>
struct Test{
T t[2];
};
int main(){
Test t{{1,2}}; // #1
// Test t1{1,2} // #2
}
Run Code Online (Sandbox Code Playgroud)
#1被GCC拒绝,而#2会被 GCC 接受。
此外,如果定义了 C 并且它的定义满足聚合类([dcl.init.aggr])的条件,假设任何依赖基类都没有虚函数和虚基类,并且初始化器是一个非-empty 花括号初始化列表或括号表达式列表,并且没有 C 的推导指南,该集合包含一个额外的函数模板,称为聚合推导候选,定义如下。令 X 1 ,...,X N是花括号初始化器列表或表达式列表的初始化器列表或指定初始化器列表的元素。对于每个 X i,让 e i是 C 或其(可能是递归的)子聚合之一的相应聚合元素,这些子聚合将由 X 初始化我 如果
- [1.5] 对于具有依赖非数组类型或具有值依赖边界的数组类型的任何聚合元素,不考虑大括号省略,并且
- [1.6] 假设每个作为包扩展的非尾随聚合元素不对应于初始化列表的任何元素,并且
- [1.7] 作为包扩展的尾随聚合元素被假定为对应于初始值设定项列表(如果有)的所有剩余元素。
如果对于任何 X i没有这样的聚合元素 e i,则不将聚合推导候选添加到集合中。聚合推导候选如上从假设构造函数 C(T 1 ,...,T n )导出
- 如果 e i是数组类型并且 x i是花括号初始化列表或字符串文字,则 …
该标准定义了几个“发生在之前”关系,这些关系将古老的“之前排序”扩展到多个线程:
\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。
为什么概念不能专门化?有理论上的原因吗?
在此代码中,
template<class T, class U>
concept always_true = true;
template<class T>
concept always_true_if_tagged = always_true<T, typename T::tag>;
struct A {
using tag = int;
};
static_assert(always_true_if_tagged<A>);
static_assert(!always_true_if_tagged<int>); //GCC says this failed
Run Code Online (Sandbox Code Playgroud)
GCC 表示第二个断言失败。Clang 和 MSVC 都同意编译它。
我最初认为它是不正确的,不需要诊断,因为temp.constr.normal#1.4
概念 ID 的范式
C<A1, A2, ..., An>是 的约束表达式的范式C,在替换A1, A2, ..., An每个C原子约束中的参数映射中的各自模板参数后。如果任何此类替换导致无效类型或表达式,则该程序格式错误;无需诊断。
替换T::typename tag是 的参数映射always_true,因此格式错误;无需诊断。
所以我的前两个问题是
解决方案之一是检查之前的嵌套类型名。所以参数映射always_true不会发生。
template<class T>
concept always_true_if_tagged =
requires …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++20 ×10
c++-concepts ×2
auto ×1
benchmarking ×1
c++11 ×1
concurrency ×1
std ×1
std-ranges ×1
templates ×1
type-traits ×1