这看起来像GCC中的错误,它无法生成std::vector<int, std::allocator<int> >
的复制构造函数。请注意,错误来自链接器,并且在编译阶段不会发生。复制构造函数用于初始化概述的任务函数的firstprivate
参数的复制函数。强制编译器生成它,例如改变
std::vector<int> a;
到
std::vector<int> a, b(a);
解决了这个问题。
这里是一个更详细的描述。 GCC转换下面的代码
#pragma omp task shared(sum)
{
sum = recursiveSumBody(vec);
}
成类似:
struct omp_data_a data_o;
data_o.vec = vec;
data_o.sum = ∑
GOMP_task(omp_fn_0, &data_o, omp_cpyfn_1, 32, 8, 1, 0, 0, 0);
// --- outlined task body ---
void omp_fn_0(struct omp_data_s & restrict data_i)
{
struct vector & vec = &data_i->vec;
*data_i->sum = recursiveSumBody<int>(vec);
std::vector<int>::~vector(vec);
}
// --- task firstprivate initialisation function ---
void omp_cpyfn_1(struct omp_data_s *data_o, struct omp_data_a *data_i)
{
data_o->sum = data_i->sum;
struct vector &d40788 = data_i->vec;
struct vector *this = &data_o->vec;
std::vector<int>::vector(this, d40788); // <--- invocation of the copy constructor
}
omp_cpyfn_1
得到由GOMP_task()
以初始化FIRSTPRIVATE参数调用。它调用std::vector<int>
的拷贝构造函数,因为(first-)private
将类型T的引用视为类型T本身,但构造函数未生成,因此目标代码无法链接。这可能是在gimplifier将代码中的错误当非参考std::vector<T, A>
被私有化的拷贝构造函数被创建,例如,用这样的代码:
...
std::vector<T, A> b;
#pragma omp task shared(sum)
{
sum = recursiveSumBody(b);
}
...
代码与英特尔18.0b编译。明确指定vec
为firstprivate
以与GCC相同的方式断开它(icpc抱怨vec
是不完整类型)。以下的解决方法,可以使用:
template<typename T, typename A>
T recursiveSumBody(std::vector<T, A> &vec) {
T sum = 0;
std::vector<T, A> *ptr = &vec;
#pragma omp task shared(sum)
{
sum = recursiveSumBody(*ptr);
}
return vec[0];
}
在这种情况下ptr
是一个指针。它的firstprivate
版本是指向相同位置的另一指针,即矢量实例。语义不同于原始代码,因为这里没有创建整个向量的私人副本,而是使用原始向量。
任何人都看过类似的东西?我想我可以使用指向矢量的第0个元素的指针,而不是'std :: vector',但如果可能的话,我宁愿不直接使用指针。 –
请注意,'libomp-dev'是与'gomp'无关的LLVM OpenMP运行时,它是'gcc'捆绑的OpenMP运行时。 – Zulan