2

I have tried writing a function which takes a ColXpr value as input:

typedef Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic> Signal2D;

void Threshold(Signal2D::ColXpr& params)
{
  params = (params >= 0.0f).template cast<float>();
}

When I try to call this function I do something like this:

Signal2D arr;
// fill it with stuff
Threshold(arr.col(0));

Then I get this compiler error:

src/core/Neuron.h:91:14: note:   no known conversion for argument 1 from ‘Eigen::DenseBase<Eigen::Array<float, -1, -1> >::ColXpr {aka Eigen::Block<Eigen::Array<float, -1, -1>, -1, 1, true>}’ to ‘Eigen::DenseBase<Eigen::Array<float, -1, -1> >::ColXpr& {aka Eigen::Block<Eigen::Array<float, -1, -1>, -1, 1, true>&}’
make: *** [src/training/Fibonacci.o] Error 1

Without reposting the entire series of code that leads to this, could someone explain what it means when the compiler says no known conversion for argument from Value to Value&? Why can't it get a reference in this instance? Note that I've seen a similar problem related to the this pointer which I've posted here:

error: no match for 'operator<<' using boost::serialisation

Could this be some peculiarity of GCC 4.9.0 or am I doing something wrong here? Please let me know if you need to see a self-contained example, it will take a while to cobble together and I thought there might be enough info here to point out an obvious error on my part.

Community
  • 1
  • 1
quant
  • 21,507
  • 32
  • 115
  • 211
  • Let me guess - `arr.col()` returns a `Signal2D` ? – M.M May 04 '14 at 05:30
  • @MattMcNabb no, `Eigen::Array::col()` returns `Eigen::ColXpr`. There was a mistake in my example code (fixed), see http://eigen.tuxfamily.org/dox/classEigen_1_1DenseBase.html#a58c77695de3b33405f01f2fdf3dc389d – quant May 04 '14 at 05:31
  • Is that the same as `Signal2D::ColXpr`? (I see you just edited what `Threshold` takes) – M.M May 04 '14 at 05:33
  • @MattMcNabb My understanding is yes. And judging from the error they *are* the same type, but please correct me if you think otherwise. – quant May 04 '14 at 05:34

3 Answers3

3

In C++, a temporary object cannot bind to a non-const reference.

I'm assuming that arr.col(0) returns an object by value. The returned value is a temporary object. This means it cannot match a parameter of type T &.

One solution:

auto temp = arr.col(0);
Threshold(temp);

I wonder if you intended for arr.col() to return a reference?

M.M
  • 138,810
  • 21
  • 208
  • 365
3

To complete previous answers, you're probably looking for the Ref<> class which will allow you to write a function that accept both columns of a matrix and vectors without templates nor copies:

void threshold(Ref<ArrayXf> params) {
    params = (params >= 0 ).cast<float>();
}
ArrayXf  a;
ArrayXXf A;
/* ... */
threshold(a);
threshold(A.col(j));
ggael
  • 28,425
  • 2
  • 65
  • 71
1

To add to the answer above:

Eigen return expressions are temporaries. E.g. ColXpr is just a small copyable object that gives you access to the array data. It is returned by value, ColXpr col(...). You can capture the ColXpr temporary with const reference but not otherwise.

However you can write:

void Threshold(Matrix::ColXpr col);

Generally, it is frowned upon to modify Eigen expression in functions. The preferred way is to write unary/binary functors/lambdas eg:

array.col(i) = array.col(i).unaryExpr(
  [](const float &value) {
    return float(value >= 0); 
  }
);

Btw, if you intend to write generic Eigen functions, use Eigen::EigenBase<B> as arguments to capture any eigen expression, see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

Boost serialization requires non-temporary reference as well, even the operand is being written to an archive.

Anycorn
  • 50,217
  • 42
  • 167
  • 261