Re: [eigen] binder2nd deprecated

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


On 4/30/2015 19:07, Gabriel wrote:
Hello all :-)

I get so many nasty warnings about: 'binder2nd' is deprecated

Can that be circumvented or will there be a replacement sometime?
Hi!

I think I may have an idea for a replacement! :-)

To start with: This warning is due to binders being deprecated in C++11:
https://thenewcpp.wordpress.com/2012/04/25/deprecated-binders-and-adaptors/
http://en.cppreference.com/w/cpp/utility/functional/binder12

You should not see this warning unless you're compiling with C++11 (or latter) standard.
Consequently, I'm assuming you're compiling with C++11 support.

Now, the question boils down to what's the C++11 replacement; there are some useful comments in the following:
http://stackoverflow.com/questions/19772691/what-replaces-binder2nd-in-c11

This gave me an idea:
http://melpon.org/wandbox/permlink/hQsgpVJeTTYFlm7j

Note how type `std::binder2nd<std::less<int>>` can be initially replaced with `decltype(std::bind(std::less<int>{}, std::placeholders::_1, 0))`.
Now, to generalize it, one could replace `0` with `T{}` or `declval<T>()` -- where `T` is the deduced correct type (here: `int`).
In order to actually find out what `T` should be, one needs to automatically infer the callable's argument type -- e.g., akin to something like this:
http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html

So, either
`decltype(std::bind(std::less<int>{}, std::placeholders::_1, std::declval<int>()))`.
or perhaps
`decltype(std::bind(std::less<int>(), std::placeholders::_1, int{}))`.
Depending on whether we want to avoid going through the constructors: http://en.cppreference.com/w/cpp/utility/declval

Now: As soon as we know the argument-type of `FUNCTOR<Scalar>` -- assume it's `T` -- I think we can use either
`decltype(std::bind(FUNCTOR<Scalar>{}, std::placeholders::_1, std::declval<T>()))`.
or perhaps
`decltype(std::bind(FUNCTOR<Scalar>, std::placeholders::_1, T{}))`.

Again, if we don't know what `T` is, I presume we can deduce it, using a solution similar to that of Boost's function traits?

It's still somewhat long-winded, so I'd suggest a simple wrapper, e.g., using alias templates:
http://en.cppreference.com/w/cpp/language/type_alias
// generally, binders are somewhat readability & maintainability unfriendly, so it's only expected that some of this unfriendliness carries over to the emulators...

Here's a one liner wrapper:
template <typename T> using binder_2nd_less = decltype(std::bind(std::less<T>(), std::placeholders::_1, T{}));

For instance, this allows to replace `std::binder2nd<std::less<int>>` with `binder_2nd_less<int>` in the code.

Finally, conditional compilation -- depending on whether C++11 is enabled -- can choose whether to use the C++11-compliant type definition (or whether to fall-back to the `std::binder2nd`).

Thoughts?

Best,

Matt


Thanks a lot :-)



In file included from /usr/local/include/eigen3/Eigen/Dense:1:
In file included from /usr/local/include/eigen3/Eigen/Core:350:
In file included from /usr/local/include/eigen3/Eigen/src/Core/ArrayBase.h:109:
/usr/local/include/eigen3/Eigen/src/Core/../plugins/ArrayCwiseUnaryOps.h:196:1: warning: 'binder2nd' is deprecated [-Wdeprecated-declarations]
EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator==,  std::equal_to)
^
/usr/local/include/eigen3/Eigen/src/Core/../plugins/ArrayCwiseUnaryOps.h:190:34: note: expanded from macro 'EIGEN_MAKE_SCALAR_CWISE_UNARY_OP'
  inline const CwiseUnaryOp<std::binder2nd<FUNCTOR<Scalar> >, const Derived> \
                                 ^
/usr/local/include/eigen3/Eigen/src/Core/PlainObjectBase.h:88:32: note: in instantiation of template class 'Eigen::ArrayBase<Eigen::Array<double, 1, 3, 1, 1, 3> >' requested here
class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
                               ^
/usr/local/include/eigen3/Eigen/src/Core/Array.h:43:12: note: in instantiation of template class 'Eigen::PlainObjectBase<Eigen::Array<double, 1, 3, 1, 1, 3> >' requested here
  : public PlainObjectBase<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
           ^
/usr/local/include/eigen3/Eigen/src/Core/IO.h:245:38: note: in instantiation of template class 'Eigen::Array<double, 1, 3, 1, 1, 3>' requested here
  return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT);
                                     ^
/home/zfmgpu/Desktop/Repository/SimulationFramework/SourceCode/Projects/SimulationFramework/CommonSource/include/GRSF/Common/SimpleLogger.hpp:160:17: note: in instantiation of function template specialization 'Eigen::operator<<<Eigen::Transpose<Eigen::Array<double, 3, 1, 0, 3, 1> > >' requested here
            m_s << t; // Push message
                ^
/home/zfmgpu/Desktop/Repository/SimulationFramework/SourceCode/Projects/SimulationFramework/Projects/GeneralRigidBodySimulationMPI/include/GRSF/Dynamics/General/MPITopologyBuilder.hpp:1005:51: note: in instantiation of function template specialization 'Logging::Log::_expression_::operator<<<Eigen::Transpose<Eigen::Array<double, 3, 1, 0, 3, 1> > >' requested here
                            "\t extent: " << "[ " << m_aabb_glo.extent().transpose() << "]" << std::endl;);






On 04/20/2015 01:39 PM, Gael Guennebaud wrote:


On Sun, Apr 19, 2015 at 12:26 AM, Matan Nassau <matan.nassau@xxxxxxxxx> wrote:
But, there is no initializer list here.

right, but without C++11, as soon as we need other ctors, we cannot distinguish between a default and value initialization. So using Matrix()=default in c++11 would lead to very different and unsafe behaviors between C++03 and C++11. This is why, IMO, initializer lists is the right solution to this problem. And of course, as Christoph said, using Matrix::Zero() is what you should do in the meantime, and/or to be compatible with C++03.

gael

 
There is an =default, yes, but maybe we can do that conditionally?

#if __cplusplus >= 201103L
Matrix()=default;
#else
#ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO
...

If Eigen supports C++11 initialization semantics it opens the door for more performant code, and for more expressive flexibility in user code. I mean, I can clearly express what I want with

Matrix3d m;

and

Matrix3d m{};

controlling the performance or behaviour in case-by-case fashion, in my code.

Eigen can do this, while still providing the current behaviour for C++03.

On Sat, Apr 18, 2015 at 15:47 Gael Guennebaud <gael.guennebaud@xxxxxxxxx> wrote:
Hi,

Eigen aims to be compatible with C++03, and initializer-lists are not supported yet. So currently Vector2d v{}; is equivalent to Vector2d v; .

See this bug entry for further discussions on initializer-lists: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=954. They will likely be supported in Eigen 3.3, and we already agreed on making the empty initializer-list initializes to 0.

In the meantime, you can compile with -DEIGEN_INITIALIZE_MATRICES_BY_ZERO, as documented there: http://eigen.tuxfamily.org/dox/TopicPreprocessorDirectives.html#title0.

cheers,
gael


On Sat, Apr 18, 2015 at 7:22 PM, Matan Nassau <matan.nassau@xxxxxxxxx> wrote:
I have a class,

 struct foo {
   foo() : v{} {}
   private:
   Eigen::Vector2d v;
 };

I just got bitten when I realized the value of v is undetermined.
I understand the default constructor of a fixed-size matrix does nothing. In particular,

 Eigen::Vector2d v{};

will create a vector with an undetermined value.

Why is that? Is this for speed?

If I value-initialize an object I expect it to initialize. To motivate, all standard templates and classes behave this way:

 std::string s{};  // assert(s=="");
 std::vector v{};  // assert(v.size() == 0);

Granted,

 std::string s;  // assert(s=="");

but if we want speed here then we can do

 template<...
 struct Matrix {
   Matrix() = default;
   // ...

This way, we'd get the best of both worlds:

 Eigen::Vector2d v;  // valid, undetermined value
 Eigen::Vector2d v{};  // assert(v==Eigen::Vector2d::Zero());


Matan






Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/