在代码审查期间,我遇到了一段代码,基本上归结为:
#include <iostream>
#include <future>
#include <thread>
int main( int, char ** )
{
std::atomic<int> x( 0 );
std::future<void> task;
for( std::size_t i = 0u; i < 5u; ++i )
{
task = std::async( std::launch::async, [&x, i](){
std::this_thread::sleep_for( std::chrono::seconds( 2u * ( 5u - i ) ) );
++x;
} );
}
task.get();
std::cout << x << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我不确定是否
我无法通过阅读互联网上的文档来回答这个问题,所以我想我会编写上面的代码段来找出我们的编译器实际上做了什么.
现在,我发现gcc-5所做的答案是优柔寡断的,这让我更加好奇:人们会认为这个任务要么是阻止的,要么是非阻塞的.
如果它是阻塞的,程序所花费的时间基本上应该是各个任务执行所花费的时间的总和.第一个需要10秒,第二个8秒,第三个6秒,第四个4秒和最后2秒.所以总共需要10 + 8 + 6 + 4 + 2 = 30秒.
如果它是非阻塞的,则应该与上一个任务一样长,即2秒 …
我想要我的课
template <class T, unsigned int n>
class X;
Run Code Online (Sandbox Code Playgroud)
创建一个std::tuple包含n类型的时间T.这有什么特别巧妙的方法吗?对于任意可变参数模板类,还有一种很好的方法吗?
这是我先做的事情:
#include <tuple>
template <class, unsigned int, class>
struct simple_repeat_helper;
template <class T, unsigned int n, class... Args>
struct simple_repeat_helper<T, n, std::tuple<Args...>>
{
typedef typename simple_repeat_helper<T, n-1, std::tuple<Args..., T>>::type type;
};
template <class T, class... Args>
struct simple_repeat_helper<T, 0, std::tuple<Args...>>
{
typedef std::tuple<Args...> type;
};
template <class T, unsigned int n>
struct simple_repeat
{
using type = typename simple_repeat_helper<T, n, std::tuple<>>::type;
};
Run Code Online (Sandbox Code Playgroud)
但实际上,我不需要这个std::tuple …
今天我在使用using关键字时遇到了问题C++11.我现在决定使用另一种方法(在下面的例子中添加为注释).你可以认为X作为一个矩阵,Y作为混入,而目的是访问的tranposed矩阵类型X在Y.取而代之的typedef荷兰国际集团X<B,A>的X<A,B>,我们采取另一种方法是功能更强大,定义一个Sibling别名,它有两个模板参数本身.
template <class A, class B>
struct X
{
using Left = A;
using Right = B;
template <class T1, class T2>
using Sibling = X<T1, T2>;
// using Reversed = X<B, A>; // What I really want and use now. :-)
};
template <class A>
struct Y
{
using Left = typename A::Left;
using Right = typename A::Right;
using …Run Code Online (Sandbox Code Playgroud) 在某些情况下std::function可以取代继承.以下两个代码片段非常相似(调用函数时的成本大致相同,签名中的用法几乎相同,在大多数情况下,std :: function也不需要我们制作额外的副本A):
struct Function
{
virtual int operator()( int ) const =0;
};
struct A
: public Function
{
int operator()( int x ) const override { return x; }
};
Run Code Online (Sandbox Code Playgroud)
使用std::function,我们可以重写为
using Function = std::function<int (int)>;
struct A
{
int operator()( int x ) const { return x; }
};
Run Code Online (Sandbox Code Playgroud)
为了更清楚,两个片段是如何相关的:它们都可以通过以下方式使用:
int anotherFunction( Function const& f, int x ) { return f( x ) + f( x ); }
int main( int …Run Code Online (Sandbox Code Playgroud) 我有两个元组std::tuple<F1, F2, ..., FN>,std::tuple<G1, G2, ..., GN>(或std::tuple<G1>aka G1).有没有什么办法一般加入这些元组成std::tuple<F1, F2, ..., FN, G1, G2, ..., GN>,如果任何类型的F1,F2,..., ,,FN ,...,没有一个默认的构造函数,但移动/可插拔?G1G2GN
有没有办法迫使C++编译器在模板实例化期间(而不是之前)对给定符号执行名称查找?
给出以下代码:
template <class T>
auto wrapper( T t ) -> decltype( f( t ) )
{
return f( t );
}
unsigned char f( int x ) { return x % 256; }
unsigned char f( unsigned char x ) { return x; }
int main( int, char ** )
{
auto x = wrapper( 3100 );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有什么我可以做的(除了将定义f移到顶部),以便使代码编译并给出相同的结果,好像所有定义f在定义之前都可用wrapper?
我找不到任何东西,可能是因为我不知道如何恰当地说出这个问题.f如果有帮助,可以假设所有参数类型都是用户定义的类型.
我知道如果没有缓存数据,访问主内存的延迟很高.这个问题是关于吞吐量的.
在常规台式PC上永远不受主内存限制的函数所需的复杂性是多少?
我读到了带宽为25-30GB/s的现代RAM(DDR3 RAM,双通道模式).据我所知,现代英特尔处理器的单核可以使用现代SIMD指令集存储每条指令最多32字节.它最多可以运行4*10 ^ 9条指令.如此有效,它可以输出大约120GB/s.给定具有8个线程的处理器,作为最坏情况估计,最大输出量将是大约960GB/s.
处理器最多可以输出可写入RAM的数据的~36倍.是否可以安全地假设每个SIMD存储或加载超过36个周期运行非加载/存储操作的任何函数(或每个常规8个字节存储或加载超过9个周期)将永远不会受到主存储器的约束?由于某些原因,这个估计值是可以显着降低还是太低?
鉴于我有:
X = (x_1, x_2, ..., x_n) // dataset, large enough to make good use of caches
a(x), b(x), c(x, y), d(x) := c(a(x), b(x)) // functions that operate on elements
A(x) := (a(x_1), a(x_2), ..., a(x_n)) // functions that operate on data sets
Run Code Online (Sandbox Code Playgroud)
我正在寻找实施更好(或更糟)的准则
D(X)
Run Code Online (Sandbox Code Playgroud)
如
C(A(X), B(X))
Run Code Online (Sandbox Code Playgroud)
鉴于第一个实现对缓存和寄存器施加了更大的压力,第二个实现具有更多的加载/存储操作.
(当然,你可以告诉我基准测试的东西,我很好.但有时候,我只是想做一个有根据的猜测,只是重新审视一些东西,当它成为一个问题或后来的瓶颈.)
使用参数包时,我觉得有点不舒服.我有一个功能
template <class ... Args>
void f( int x, Args ... args, int y )
{}
Run Code Online (Sandbox Code Playgroud)
当然使用它像这样工作:
f( 5, 3 );
Run Code Online (Sandbox Code Playgroud)
我想知道为什么以下调用失败:
f( 5, 3.f, 3 );
Run Code Online (Sandbox Code Playgroud)
这似乎是对我的直接使用参数包,但根据编译器Args没有扩展.
当然,我可以轻易地替换f为:
template <class ... Args>
void f( int x, Args ... args )
{
static_assert( sizeof...( args ) >= 1, ... );
extract y from args ...
}
Run Code Online (Sandbox Code Playgroud)
问题:
为什么我不能使用这样的参数包?似乎编译器可以轻松创建替换代码.或者f()上面更换有什么问题吗?
如果参数的顺序对我来说真的很重要,那么解决这个问题的最佳方法是什么?(想想std::transform任意数量的输入迭代器.)
为什么在上面的情况下不禁止使用参数包?我认为,这是因为它们可以明确地扩展,例如f<float>( 5, 3.f, 3 )?
在我的代码中,我必须考虑一个数组数组,其中内部数组的尺寸是固定的。为了利用STL算法,将数据实际存储为数组数组很有用,但是我还需要将该数据传递给C库,该库采用扁平化的C样式数组。
能够以可移植的方式廉价地转换(即展平)多维数组将是很棒的。我会坚持一个非常简单的案例,真正的问题是更笼统的。
struct my_inner_array { int data[3]; };
std::vector<my_inner_array> x(15);
Run Code Online (Sandbox Code Playgroud)
是
&(x[0].data[0])
Run Code Online (Sandbox Code Playgroud)
指向大小为45 * sizeof(int)的连续内存块的指针,该内存块包含与x相同的条目?还是我需要担心对齐?恐怕这将对我有用(至少对于某些数据类型和内部数组大小而言),但它不是可移植的。
在编写类似C++11 std::tuple的类并尝试使用它编译时,我遇到了一个非常奇怪的情况g++-4.7.我基本上需要的是一个包裹类型的元组.我写了这样的东西:
#include <tuple>
template <class T>
struct Wrapper { T x; };
template <class... Types>
using Tuple = std::tuple<Wrapper<Types>...>;
template <class... Types>
struct X
{
using MyTuple = Tuple<Types...>;
};
int main( int argc, char** argv )
{
// Tuple<int,int> t; // (1)
using Y = X<int,int>;
Y y; // (2)
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我做了以下观察:
(1),它会编译.(1)和(2),它编译为好.1的错误消息:
test.cpp: In instantiation of ‘struct X<int, int>’:
test.cpp:22:4: required from …Run Code Online (Sandbox Code Playgroud) 有时我倾向于编写仿函数,而不是为了在函数调用之间维护状态,而是因为我想捕获函数调用之间共享的一些参数.举个例子:
class SuperComplexAlgorithm
{
public:
SuperComplexAlgorithm( unsigned int x, unsigned int y, unsigned int z )
: x_( x ), y_( y ), z_( z )
{}
unsigned int operator()( unsigned int arg ) const /* yes, const! */
{
return x_ * arg * arg + y_ * arg + z_;
}
private:
// Lots of parameters are stored as member variables.
unsigned int x_, y_, z_;
};
// At the call site:
SuperComplexAlgorithm a( 3, 4, 5 ); …Run Code Online (Sandbox Code Playgroud) 我目前正在编写一个处理通用容器的函数模板.我想用std::begin()和std::end(),因上述原因在这一问题.我的问题是,我是否应该使用:
std::begin( myContainer )
Run Code Online (Sandbox Code Playgroud)
要么:
using namespace std; // Better use: "using std::begin"
begin( myContainer )
Run Code Online (Sandbox Code Playgroud)
或者,换句话说,是否可以begin()在std命名空间内重载?我是否应该允许我的函数用户在其他地方重载全局命名空间中的begin()函数?STL如何处理它?
c++ ×12
c++11 ×9
templates ×4
tuples ×2
assembly ×1
boost-bind ×1
c ×1
c++14 ×1
future ×1
g++ ×1
name-lookup ×1
performance ×1
stl ×1
x86 ×1