CRTP:与表达式模板的编译器相关问题 [英] CRTP: Compiler dependent issue with Expression Template
问题描述
我在编译器依赖的问题中遇到以下代码(存储在crtp.cc中):
I incurred in a compiler dependent issue with the following code (stored in crtp.cc):
#include <vector>
#include <cassert>
#include <iostream>
template < class Derived >
class AlgebraicVectorExpression {
public:
typedef std::vector<double>::size_type SizeType;
typedef std::vector<double>::value_type ValueType;
typedef std::vector<double>::reference ReferenceType;
SizeType size() const {
return static_cast<const Derived&>(*this).size();
}
ValueType operator[](SizeType ii) const {
return static_cast<const Derived&>(*this)[ii];
}
operator Derived&() {
return static_cast<Derived&>(*this);
}
operator const Derived&() const {
return static_cast< const Derived& >(*this);
}
};
template< class T1, class T2>
class AlgebraicVectorSum : public AlgebraicVectorExpression< AlgebraicVectorSum<T1,T2> > {
const T1 & a_;
const T2 & b_;
typedef typename AlgebraicVectorExpression< AlgebraicVectorSum<T1,T2> >::SizeType SizeType;
typedef typename AlgebraicVectorExpression< AlgebraicVectorSum<T1,T2> >::ValueType ValueType;
public:
AlgebraicVectorSum(const AlgebraicVectorExpression<T1>& a, const AlgebraicVectorExpression<T1>& b) :
a_(a), b_(b) {
assert(a_.size() == b_.size());
}
SizeType size() const {
return a_.size();
}
ValueType operator[](SizeType ii) const {
return (a_[ii] + b_[ii]);
}
};
template< class T1, class T2>
const AlgebraicVectorSum<T1,T2>
operator+(const AlgebraicVectorExpression<T1>& a, const AlgebraicVectorExpression<T2>& b) {
return AlgebraicVectorSum<T1,T2>(a,b);
}
class AlgebraicVector : public AlgebraicVectorExpression<AlgebraicVector>{
std::vector<double> data_;
public:
SizeType size() const {
return data_.size();
}
ValueType operator[](SizeType ii) const {
return data_[ii];
}
ValueType& operator[](SizeType ii) {
return data_[ii];
}
AlgebraicVector(SizeType n) : data_(n,0.0) {
};
template< class T>
AlgebraicVector(const AlgebraicVectorExpression<T>& vec) {
const T& v = vec;
data_.resize(v.size());
for( SizeType idx = 0; idx != v.size(); ++idx) {
data_[idx] = v[idx];
}
}
};
int main() {
AlgebraicVector x(10);
AlgebraicVector y(10);
for (int ii = 0; ii != 10; ++ii)
x[ii] = y[ii] = ii;
AlgebraicVector z(10);
z = x + y;
for(int ii = 0; ii != 10; ++ii)
std::cout << z[ii] << std::endl;
return 0;
}
事实上,当我编译它:
$ g++ --version
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -O0 -g crtp.cc
我获得: / p>
I obtain:
$ ./a.out
0
2
4
6
8
10
12
14
16
18
这是预期的行为。当我使用icpc时:
which is the expected behavior. When I use icpc:
$ icpc --version
icpc (ICC) 12.1.0 20110811
Copyright (C) 1985-2011 Intel Corporation. All rights reserved.
$ icpc -g -O0 crtp.cc
c>分段故障。正在运行
I obtain instead a Segmentation fault
. Running
valgrind --tool=memcheck ./a.out
指向源
AlgebraicVectorExpression<AlgebraicVector>::operator AlgebraicVector const&() const (crtp.cc:29)
到C ++和我花了很多时间搜索一个bug没有任何结果,我想问一个更有经验的人的意见,以了解这个问题是否是由于一些错误,我介绍(如我所料)或编译器错误。
As I am quite new to C++ and I spent quite a time searching for a bug without any result, I would like to ask the opinion of someone more experienced to understand if this issue is due to some error I introduced (as I expect) or to a compiler bug.
编辑:
我在Mike Seymour的回答后更改了现在的代码。现在我没有得到编译器警告,但我仍然得到相同的行为,以前(具有相同的valgrind响应)。有没有人试图用英特尔编译?
Edit: I changed the code as it is now, after the answer from Mike Seymour. Now I don't get compiler warnings, but I still get the same behavior as before (with the same valgrind response). Did anybody try to compile with Intel?
编辑:
我试图编译代码在表达式模板页面。我获得了与我提供的示例相同的确切行为。
Edit: I tried to compile the code in the Expression Templates page of Wikipedia. I obtained the same exact behavior as with the example I provided.
编辑:
我进一步调查了问题,与英特尔 icpc
编译操作符
operator const Derived&() const {
return static_cast< const Derived& >(*this);
}
递归调用自身。一个解决方法我发现是用一个方法替换这个运算符:
recursively calls itself. One workaround I found is to substitute this operator with a method:
const Derived& get_ref() const {
return static_cast< const Derived& >(*this);
}
并相应地修改各种类的构造函数。
and modify the constructors of the various classes accordingly. Can anybody tell which of these two behaviors is right possibly pointing to the standard to explain that?
推荐答案
任何人都应该总是启用编译器警告;他们经常可以发现微妙的问题。在这种情况下:
You should always enable compiler warnings; they can often spot subtle problems. In this case:
g++ -Wall -Wextra test.cpp
test.cpp: In member function ‘const typename AlgebraicVectorExpression<AlgebraicVectorSum<T1, T2> >::ValueType& AlgebraicVectorSum<T1, T2>::operator[](typename AlgebraicVectorExpression<AlgebraicVectorSum<T1, T2> >::SizeType) const [with T1 = AlgebraicVector, T2 = AlgebraicVector]’:
test.cpp:90: instantiated from ‘AlgebraicVector::AlgebraicVector(const AlgebraicVectorExpression<T1>&) [with T = AlgebraicVectorSum<AlgebraicVector, AlgebraicVector>]’
test.cpp:103: instantiated from here
test.cpp:52: warning: returning reference to temporary
这会告诉你问题:
const ValueType& operator[](SizeType ii) const {
return (a_[ii] + b_[ii]);
}
表达式的结果是一个临时的, ,所以函数返回一个悬挂的引用到不存在的对象。这个操作符将不得不返回值,而不应该实现非 - const
重载,因为没有值要修改。
The result of the expression is a temporary, destroyed at the end of that line, so the function is returning a dangling reference to a non-existent object. This operator will have to return by value instead, and you shouldn't implement the non-const
overload since there is no value to modify.
这篇关于CRTP:与表达式模板的编译器相关问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!