8

I got different results using auto and using Vector when summing two vectors.

My code:

#include "stdafx.h"
#include <iostream>
#include "D:\externals\eigen_3_1_2\include\Eigen\Geometry"

typedef Eigen::Matrix<double, 3, 1>       Vector3;

void foo(const Vector3& Ha, volatile int j) 
{
    const auto resAuto = Ha + Vector3(0.,0.,j * 2.567);
    const Vector3 resVector3 = Ha + Vector3(0.,0.,j * 2.567);

    std::cout << "resAuto = " << resAuto <<std::endl;
    std::cout << "resVector3 = " << resVector3 <<std::endl;
}

int main(int argc, _TCHAR* argv[])
{
    Vector3 Ha(-24.9536,-29.3876,65.801);
    Vector3 z(0.,0.,2.567);

    int j = 7;

    foo(Ha,j);
    return 0;
}

The results:

resAuto = -24.9536, -29.3876,65.801

resVector3 = -24.9536,-29.3876,83.77

Press any key to continue . . .

I understand that Eigen does internal optimization that generate different results. But it looks like a bug in Eigen and C++11.

qwerty_so
  • 33,313
  • 7
  • 58
  • 83
  • 1
    If it sounds like "a bug in Eigen and C++11", it probably isn't. Read the documentation again carefully, paying careful attention to expression templates. – Kerrek SB Jun 28 '15 at 11:34
  • It works successfully for me with eigen 3.2.2. – user2658323 Jun 29 '15 at 15:50
  • Expression templates and other classes that return proxy types (vector::operator[](size_t)) can be surprising when used with auto. Instead of getting the sum of your vectors you are getting a type that stores the expression of the sum of your two vectors. This is a template optimization that is often used for large objects live matrices. In other news, there was a proposal for 'operator auto' that would have allowed the Eigen class author to return an actual Vector3 in your case. I know gcc and I think clang have snuck it in. Maybe hack your own 'operator auto' and see. – emsr Jun 29 '15 at 20:04

1 Answers1

4

The auto keyword tells the compiler to "guess" the best object based on the right hand side of the =. You can check the results by adding

std::cout << typeid(resAuto).name() <<std::endl;
std::cout << typeid(resVector3).name() <<std::endl;

to foo (don't forget to include <typeinfo>).

In this case, after constructing the temporary Vector3, the operator+ method is called, which creates a CwiseBinaryOp object. This object is part of Eigens lazy evaluation (can increase performance). If you want to force eager evaluation (and therefore type determination), you could use

const auto resAuto = (Ha + Vector3(0.,0.,j * 2.567)).eval();

instead of your line in foo.

A few side notes:

  • Vector3 is identical to the Vector3d class defined in Eigen
  • You can use #include <Eigen/Core> instead of #include <Eigen/Geometry> to include most of the Eigen headers, plus certain things get defined there that should be.
Avi Ginsburg
  • 9,897
  • 3
  • 26
  • 54