由于Coroutines TS在Kona的ISO会议上已被C ++ 20接受,因此我开始自己研究一下它们。Clang已经对协程提供了不错的支持,但是仍然缺乏库支持的实现。特别是,Awaitable类型,如std::future
,std::generator
等方面都尚未实现。
因此,我将自己置于std::future
等待之中。我主要关注James McNellis在CppCon 2016上的演讲,特别是这张幻灯片:
这是2019年,实际上我在这张幻灯片上的(可能未经测试?)代码上遇到了一些麻烦:
operator co_await
不再是一回事吗?相反,应该使用可选await_transform
的promise_type
。不过,不确定我是否正确。then
future 的继续按值捕获句柄,但resume
成员函数不是const限定的。我通过制作lambda解决了这一问题mutable
。另外,在我的libc ++版本中,then
和is_ready
尚不可用,std::future
但std::experimental::future
仍缺少其中的一部分。为了避免与Awaiter打交道并实现将来的延续,我编写了派生的Future类,它是Awaitable和Awaiter。根据我的理解,最终两者都会成立std::future
。您可以在Compiler Explorer上看到我的示例。它确实可以编译。
但是,它也确实存在段错误。这发生在await_resume
何时get()
调用。这实际上不足为奇,因为此时valid()
回报false
(调用get()
UB)。我认为这是因为当then
用于继续将来时,原始的将来对象已移入异步将来,从而使旧的将来无效(*this
当时await_resume
称为,所以在移动之后)。我的实现从这个答案和我在GitHub上找到的代码then
大致上受到启发。这些可能并不理想,但是cppreference明确指出了call的后置条件,因此我认为脱离原来的未来是正确的。 valid() == …
我正在实现一个二维数组容器(比如boost::multi_array<T,2>
,主要用于练习).为了使用双索引表示法(a[i][j]
),我引入了一个代理类row_view
(const_row_view
但我不关心这里的constness),它保留了指向行的开头和结尾的指针.
我还希望能够分别遍历行和行内的元素:
matrix<double> m;
// fill m
for (row_view row : m) {
for (double& elem : row) {
// do something with elem
}
}
Run Code Online (Sandbox Code Playgroud)
现在,matrix<T>::iterator
类(用于遍历行)在row_view rv;
内部保持私有以跟踪迭代器指向的行.当然,iterator
也实现了dereferenciation功能:
operator*()
,人们通常想要返回一个参考.相反,这里正确的做法似乎返回一个row_view
值(即返回私有的副本row_view
).这确保了当迭代器前进时,row_view
静止指向前一行.(在某种程度上,row_view
行为就像参考一样).因为operator->()
,我不太确定.我看到两个选择:
返回指向row_view
迭代器私有的指针:
row_view* operator->() const { return &rv; }
Run Code Online (Sandbox Code Playgroud)返回指向新的指针row_view
(私有指针的副本).由于存储生命周期,必须在堆上分配.为了确保清理,我将其包装成unique_ptr
:
std::unique_ptr<row_view> operator->() const {
return std::unique_ptr<row_view>(new row_view(rv));
}
Run Code Online (Sandbox Code Playgroud)显然,2更正确.如果迭代器 …
我尝试编写一个自定义STL样式的容器.为简单起见,我们说它是一个列表.我查找了定义这样一个容器的标准方法:
template <typename T, typename A = std::allocator<T> > class mylist;
Run Code Online (Sandbox Code Playgroud)
现在,我想使用嵌套类来管理列表的节点:
(inside mylist)
class node {
T data;
node *next;
}
Run Code Online (Sandbox Code Playgroud)
我的理解是,我不需要template
在定义之前放置一个说明符,node
因为编译器将为mylist<T,A>::node
每个mylist
模板参数组合实例化单独的类.
但是,现在我需要为类型T
本身的数据分配内存,而且还需要为它们的包装器分配内存node
.因此,我希望默认模板参数是类型std::allocator<mylist<T>::node>
.但是,在那时,mylist
尚未声明,编译器可以理解为难过:
error: `mylist' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)
如何解决这个难题?有两个限制:
node
嵌套,因为它需要访问分配器实例mylist
.例如,我已经operator=
声明node
了许多内存管理递归发生的地方.对于列表而言,这可能是过度的,您可以从内部执行此操作mylist
,从而降低node
on 的参数依赖性A
,但这对于我正在实现的数据结构至关重要.我一直在尝试编写一个特征,该特征需要一种类型来实现Add
(以及进一步的向量空间的其他操作)及其自身及其引用。下面是一个小例子,说明了我遇到的问题:
use std::ops::Add;
#[derive(Debug)]
struct MyVec<T>(Vec<T>);
impl<'a, 'b, T: Copy + Add> Add<&'a MyVec<T>> for &'b MyVec<T> {
type Output = MyVec<T::Output>;
fn add(self, other: &'a MyVec<T>) -> Self::Output {
/* ... */
}
}
impl<'a, T: Copy + Add> Add<MyVec<T>> for &'a MyVec<T> {
/* ... */
}
impl<'a, T: Copy + Add> Add<&'a MyVec<T>> for MyVec<T> {
/* ... */
}
impl<T: Copy + Add> Add<MyVec<T>> for MyVec<T> {
/* ... */
}
trait Addable: Add<Self, …
Run Code Online (Sandbox Code Playgroud) 我认为这是一个标准的菜鸟问题,但在整个上午搜索网络后,我决定不管怎么说.我在Mac OS 10.9上,我想从Fortran程序中调用LAPACK特征值例程.我有幸在昨天被介绍给Fortran,所以请原谅任何愚蠢的错误.
这是我想要运行的最小例子:
program eigtest
complex A(3,3)
real eigs(3)
A(1,1) = cmplx(1,0)
A(1,2) = cmplx(0,2)
A(1,3) = cmplx(3,0)
A(2,1) = cmplx(0,-2)
A(2,2) = cmplx(5,0)
A(2,3) = cmplx(1,-1)
A(3,1) = cmplx(3,0)
A(3,2) = cmplx(1,1)
A(3,3) = cmplx(7,0)
call heevd(A, eigs)
write(*,*) eigs
end
Run Code Online (Sandbox Code Playgroud)
我了解到在OS X上,LAPACK是Accelerate框架的一部分,所以我尝试了以下方法:
gfortran -o eigtest -framework accelerate eigtest.f95
Run Code Online (Sandbox Code Playgroud)
但链接器抱怨:
Undefined symbols for architecture x86_64:
"_heevd_", referenced from:
_MAIN__ in ccleuVFO.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud) 我有两个 numpy 数组,第一个,A
是一维的,第二个, B
, 在我想到的应用程序中是二维的,但实际上可以有任何维度。的每个索引都B
覆盖与 的单个索引相同的范围A
。
现在,我想排序A
(按降序)但想排列每个维度B
。从数学上讲,如果P
是排序的排列矩阵A
,我想B
根据 进行变换np.dot(P, np.dot(B, P.T))
。例如,考虑这个例子,其中排序恰好对应于颠倒顺序:
In [1]: import numpy as np
In [2]: A = np.array([1,2,3])
In [3]: B = np.random.rand(3,3); B
Out[3]:
array([[ 0.67402953, 0.45017072, 0.24324747],
[ 0.40559793, 0.79007712, 0.94247771],
[ 0.47477422, 0.27599007, 0.13941255]])
In [4]: # desired output:
In [5]: A[::-1]
Out[5]: array([3, 2, 1])
In [6]: B[::-1,::-1]
Out[6]:
array([[ 0.13941255, 0.27599007, 0.47477422],
[ …
Run Code Online (Sandbox Code Playgroud) 假设某些类foo
有两个自定义构造函数,比如说foo::foo(bar const &)
和foo::foo(baz const &)
.根据某些条件调用任何一种都是好的风格.例如:
bar a;
baz b;
foo my_foo;
if (...) {
my_foo = foo(a);
} else {
my_foo = foo(b);
}
Run Code Online (Sandbox Code Playgroud)
将需要foo
默认构造(在我想到的具体情况下这不是很明智)并且基本上浪费时间(和内存)来创建(和删除)默认构造的临时对象.由于范围,不能my_foo
在if或else块内声明.
另一种方法是使用指针和构造new
.这样效率较低(间接,堆分配)并且可能不安全(不保证指针不悬空;需要delete
,尽管后者可以通过使用来处理std::unique_ptr
).
我找到了一种方法:
foo my_foo = (...) ? foo(a) : foo(b);
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为三元运算符保证是详尽的,因此范围不是问题.
我不是三元运算符的忠实粉丝,可能想在调用ctors之前在条件块中做一些其他的事情.有没有一种优雅的方法来实现传统的if-else语法相同的东西?
请考虑Rust中的以下最小示例:
const FOOBAR: usize = 3;
trait Foo {
const BAR: usize;
}
struct Fubar();
impl Foo for Fubar {
const BAR: usize = 3;
}
struct Baz<T>(T);
trait Qux {
fn print_bar();
}
impl<T: Foo> Qux for Baz<T> {
fn print_bar() {
println!("bar: {}", T::BAR); // works
println!("{:?}", [T::BAR; 3]); // works
println!("{:?}", [1; FOOBAR]); // works
println!("{:?}", [1; T::BAR]); // this gives an error
}
}
fn main() {
Baz::<Fubar>::print_bar();
}
Run Code Online (Sandbox Code Playgroud)
编译器给出以下错误:
error[E0599]: no associated item named `BAR` …
Run Code Online (Sandbox Code Playgroud)