Disable temporary binding of Eigen expression to const references
Asked Answered
B

1

2

I am trying to write a function that accepts only lvalue Eigen expressions passed via const references. My first idea was to keep only the overload const Eigen::MatrixBase<Derived>& and delete the Eigen::MatrixBase<Derived>&& one. To my surprise, the deleted function was not part of the overload candidate set. So I tried the code below

#include <iostream>
#include <Eigen/Dense>

#define PRINT_MY_NAME std::cout << __PRETTY_FUNCTION__ << '\n'

template<typename Derived>
void f(const Eigen::MatrixBase<Derived>&) // (1)
{
    PRINT_MY_NAME;
}

template<typename Derived>
void f(Eigen::MatrixBase<Derived>&&)      // (2)
{
    PRINT_MY_NAME;
}

int main()
{
    Eigen::MatrixXd A;

    f(A);     // invokes (1)
    f(A + A); // invokes also (1) !!!
}

which outputs (gcc5.2)

void f(const Eigen::MatrixBase&) [with Derived = Eigen::Matrix < double, -1, -1>]

void f(const Eigen::MatrixBase&) [with Derived = Eigen::CwiseBinaryOp < Eigen::internal::scalar_sum_op < double>, const Eigen::Matrix < double, -1, -1>, const Eigen::Matrix < double, -1, -1> >]

so clearly the rvalue overload is not considered. It is now clear for me that the second one is not a better match, since I pass a rvalue Eigen expression, which is convertible to Eigen::MatrixBase<>, but is not the exact same type. Now comes my question:

  • How can I disable or detect rvalue Eigen expressions passed as parameters for f? The issue is that an expression can have an arbitrary type (Eigen uses expression templates), like CwiseBinaryOp<...CwiseBinaryOp<...>> and so on. This is part of a larger problem in which I have a utility make-like function which takes a lvalue and binds it to a const reference expression in a class. If the expression is a rvalue, then all bets are off, since reference binding is not propagating via a constructor argument, so I want to forbid passing rvalue Eigen expressions.
Britzka answered 18/10, 2015 at 18:55 Comment(4)
Interesting, I do not have the same result while trying to make a minimal example.Drunken
@PiotrSkotnicki Yes probably that's why the second overload is not considered. The question is how can I enforce it?Britzka
@MatthieuM. I believe it has to do with the "guts" of Eigen, and how it implements the expression templates. Did you also try the exact code above? I'd be very surprised if you get (2) invoked.Britzka
I don't have Eigen, and it's not available on online compilers I know about, so no I didn't test with Eigen. Still, it ought to be reducible anyway.Drunken
B
2

I think I found what was going on: the result of the expression template A + A was a const, so there was a CV-mismatch. Adding const to the second overload does it:

template<typename Derived>
void f(const Eigen::MatrixBase<Derived>&&)      // (2)
{
    PRINT_MY_NAME;
}
Britzka answered 18/10, 2015 at 19:17 Comment(1)
Dammit... didn't they get the memo that const on return types is smelly :xDrunken

© 2022 - 2024 — McMap. All rights reserved.