Note that there are some explanatory texts on larger screens.

plurals
  1. POCRTP: Compiler dependent issue with Expression Template
    text
    copied!<p>I incurred in a compiler dependent issue with the following code (stored in crtp.cc):</p> <pre><code>#include &lt;vector&gt; #include &lt;cassert&gt; #include &lt;iostream&gt; template &lt; class Derived &gt; class AlgebraicVectorExpression { public: typedef std::vector&lt;double&gt;::size_type SizeType; typedef std::vector&lt;double&gt;::value_type ValueType; typedef std::vector&lt;double&gt;::reference ReferenceType; SizeType size() const { return static_cast&lt;const Derived&amp;&gt;(*this).size(); } ValueType operator[](SizeType ii) const { return static_cast&lt;const Derived&amp;&gt;(*this)[ii]; } operator Derived&amp;() { return static_cast&lt;Derived&amp;&gt;(*this); } operator const Derived&amp;() const { return static_cast&lt; const Derived&amp; &gt;(*this); } }; template&lt; class T1, class T2&gt; class AlgebraicVectorSum : public AlgebraicVectorExpression&lt; AlgebraicVectorSum&lt;T1,T2&gt; &gt; { const T1 &amp; a_; const T2 &amp; b_; typedef typename AlgebraicVectorExpression&lt; AlgebraicVectorSum&lt;T1,T2&gt; &gt;::SizeType SizeType; typedef typename AlgebraicVectorExpression&lt; AlgebraicVectorSum&lt;T1,T2&gt; &gt;::ValueType ValueType; public: AlgebraicVectorSum(const AlgebraicVectorExpression&lt;T1&gt;&amp; a, const AlgebraicVectorExpression&lt;T1&gt;&amp; 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&lt; class T1, class T2&gt; const AlgebraicVectorSum&lt;T1,T2&gt; operator+(const AlgebraicVectorExpression&lt;T1&gt;&amp; a, const AlgebraicVectorExpression&lt;T2&gt;&amp; b) { return AlgebraicVectorSum&lt;T1,T2&gt;(a,b); } class AlgebraicVector : public AlgebraicVectorExpression&lt;AlgebraicVector&gt;{ std::vector&lt;double&gt; data_; public: SizeType size() const { return data_.size(); } ValueType operator[](SizeType ii) const { return data_[ii]; } ValueType&amp; operator[](SizeType ii) { return data_[ii]; } AlgebraicVector(SizeType n) : data_(n,0.0) { }; template&lt; class T&gt; AlgebraicVector(const AlgebraicVectorExpression&lt;T&gt;&amp; vec) { const T&amp; 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 &lt;&lt; z[ii] &lt;&lt; std::endl; return 0; } </code></pre> <p>In fact when I compile it with:</p> <pre><code>$ 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 </code></pre> <p>I obtain:</p> <pre><code>$ ./a.out 0 2 4 6 8 10 12 14 16 18 </code></pre> <p>which is the expected behavior. When I use icpc:</p> <pre><code>$ icpc --version icpc (ICC) 12.1.0 20110811 Copyright (C) 1985-2011 Intel Corporation. All rights reserved. $ icpc -g -O0 crtp.cc </code></pre> <p>I obtain instead a <code>Segmentation fault</code>. Running</p> <pre><code>valgrind --tool=memcheck ./a.out </code></pre> <p>points to line 29 in the sources </p> <pre><code>AlgebraicVectorExpression&lt;AlgebraicVector&gt;::operator AlgebraicVector const&amp;() const (crtp.cc:29) </code></pre> <p>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.</p> <p><strong>Edit</strong>: 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?</p> <p><strong>Edit</strong>: I tried to compile the code in the <a href="http://en.wikipedia.org/wiki/Expression_templates%20Wikipedia" rel="nofollow">Expression Templates</a> page of Wikipedia. I obtained the same exact behavior as with the example I provided.</p> <p><strong>Edit</strong>: I have investigated the issue further and it seems that compiling with Intel <code>icpc</code> the operator</p> <pre><code>operator const Derived&amp;() const { return static_cast&lt; const Derived&amp; &gt;(*this); } </code></pre> <p>recursively calls itself. One workaround I found is to substitute this operator with a method:</p> <pre><code>const Derived&amp; get_ref() const { return static_cast&lt; const Derived&amp; &gt;(*this); } </code></pre> <p>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?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload