универсальный обратный вызов функции с собственными типами в качестве параметров - PullRequest
0 голосов
/ 13 сентября 2018

Я пытаюсь передать функцию, используя Eigen объекты в качестве входов и выходов в качестве обратного вызова для другой функции. Я не могу найти способ правильно обработать const параметры. Например, у меня есть эта функция копирования:

//a generic function copying a matrix into another
template<
  typename DerivedV1,
  typename DerivedV2
  >
void copy
(
  const Eigen::MatrixBase<DerivedV1> & v1,
  Eigen::MatrixBase<DerivedV2> const & v2 //Eigen const hack, this is not const
)
{
  Eigen::MatrixBase<DerivedV2> & v2_cast = 
    const_cast< Eigen::MatrixBase<DerivedV2> & >(v2) ;
  v2_cast = v1 ;
}

Я знаю, что выходные параметры могут считаться плохой практикой , но я пытаюсь следовать правилам кодирования libigl . В качестве ссылки я вызываю эту функцию в другой функции, это будет работать.

//reference non generic behaviour
template<
  typename DerivedV1,
  typename DerivedV2
  >
void reference
(
  const Eigen::MatrixBase<DerivedV1> & V1,
  Eigen::MatrixBase<DerivedV2> & V2 //Eigen const hack not necessary for the example
) 
{
  copy(V1.row(0), V2.row(0)) ;
}

Теперь я хотел бы получить универсальность для функции копирования.

//generic without constness,deduction fails with a template function as a parameter
template<
  typename DerivedV1,
  typename DerivedV2,
  typename Callback
  >
void generic
(
  Eigen::MatrixBase<DerivedV1> & V1, //no const here, this is my problem
  Eigen::MatrixBase<DerivedV2> & V2,
  Callback callback
) 
{
  callback(V1.row(0), V2.row(0)) ;
}

Но автоматическое удержание шаблона из параметров не будет выводить параметры шаблона для обратного вызова. Единственное решение, которое я нашел до сих пор, - это ужасная перегрузка, я ей не горжусь и открыт для предложений.

//overload to help template deduction
template<
  typename DerivedV1,
  typename DerivedV2
  >
void generic
(
  Eigen::MatrixBase<DerivedV1> & V1,
  Eigen::MatrixBase<DerivedV2> & V2,
  void(*callback)(
    const Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
    Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
  )
) 
{
  generic<
    DerivedV1, 
    DerivedV2, 
    void(*)(
      const Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
      Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
    )
    >(V1, V2, callback) ;
}

и это работает, но мне не удается обработать const в первом параметре generic:

//desired generic with the const parameter
template<
  typename DerivedV1,
  typename DerivedV2,
  typename Callback
  >
void generic_const
(
  const Eigen::MatrixBase<DerivedV1> & V1, //here is the desired const
  Eigen::MatrixBase<DerivedV2> & V2,
  Callback callback
) 
{
  callback(V1.row(0), V2.row(0)) ;
}

//attempt for an overload to help template deduction
template<
  typename DerivedV1,
  typename DerivedV2
  >
void generic_const
(
  const Eigen::MatrixBase<DerivedV1> & V1,
  Eigen::MatrixBase<DerivedV2> & V2,
  void(*callback)(
    const Eigen::MatrixBase< decltype(std::declval< const Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
    Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
  )
) 
{
  generic_const<
    DerivedV1, 
    DerivedV2, 
    void(*)(
      const Eigen::MatrixBase< decltype(std::declval< const Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
      Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
    )
    >(V1, V2, callback) ;
}

int main() {
  Eigen::Matrix3f m1 ;
  m1.setRandom() ;

  Eigen::Matrix3f m2 ;
  m2.setRandom() ;

  std::cout << "== random m1 ==" << std::endl << m1 << std::endl ;
  std::cout << "== random m2 ==" << std::endl << m2 << std::endl ;

  reference(m1, m2) ;

  std::cout << "== reference behaviour ==" << std::endl << m2 << std::endl ;

  m2.setRandom() ;

  std::cout << "== random m2 ==" << std::endl << m2 << std::endl ;

  //this is ok
  generic(m1, m2, copy) ;
  //this will not compile

  std::cout << "== final m2 ==" << std::endl << m2 << std::endl ;

  return 0 ;
}

Вот ошибка

error: invalid initialization of reference of type 
‘const Eigen::MatrixBase<const Eigen::Block<const Eigen::Matrix<float, 3, 3>, 1, 3, false> >&’ 
from expression of type 
‘Eigen::DenseBase<Eigen::Matrix<float, 3, 3> >::ConstRowXpr’ 
{aka ‘const Eigen::Block<const Eigen::Matrix<float, 3, 3>, 1, 3, false>’}

Полный пример приведен в следующем фрагменте.

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

//a generic function copying a matrix into another
template<
  typename DerivedV1,
  typename DerivedV2
  >
void copy
(
  const Eigen::MatrixBase<DerivedV1> & v1,
  Eigen::MatrixBase<DerivedV2> const & v2 //Eigen const hack, this is not const
)
{
  Eigen::MatrixBase<DerivedV2> & v2_cast = 
    const_cast< Eigen::MatrixBase<DerivedV2> & >(v2) ;
  v2_cast = v1 ;
}

//reference non generic behaviour
template<
  typename DerivedV1,
  typename DerivedV2
  >
void reference
(
  const Eigen::MatrixBase<DerivedV1> & V1,
  Eigen::MatrixBase<DerivedV2> & V2 //Eigen const hack is not necessary in this example
) 
{
  copy(V1.row(0), V2.row(0)) ;
}

//generic without constness,deduction fails with a template function as a parameter
template<
  typename DerivedV1,
  typename DerivedV2,
  typename Callback
  >
void generic
(
  Eigen::MatrixBase<DerivedV1> & V1, //no const here this is my problem
  Eigen::MatrixBase<DerivedV2> & V2,
  Callback callback
) 
{
  callback(V1.row(0), V2.row(0)) ;
}

//overload to help template deduction
template<
  typename DerivedV1,
  typename DerivedV2
  >
void generic
(
  Eigen::MatrixBase<DerivedV1> & V1,
  Eigen::MatrixBase<DerivedV2> & V2,
  void(*callback)(
    const Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
    Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
  )
) 
{
  generic<
    DerivedV1, 
    DerivedV2, 
    void(*)(
      const Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
      Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
    )
    >(V1, V2, callback) ;
}

//desired generic with the const parameter
template<
  typename DerivedV1,
  typename DerivedV2,
  typename Callback
  >
void generic_const
(
  const Eigen::MatrixBase<DerivedV1> & V1,
  Eigen::MatrixBase<DerivedV2> & V2,
  Callback callback
) 
{
  callback(V1.row(0), V2.row(0)) ;
}

//attempt for an overload to help template deduction
template<
  typename DerivedV1,
  typename DerivedV2
  >
void generic_const
(
  const Eigen::MatrixBase<DerivedV1> & V1,
  Eigen::MatrixBase<DerivedV2> & V2,
  void(*callback)(
    const Eigen::MatrixBase< decltype(std::declval< const Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
    Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
  )
) 
{
  generic_const<
    DerivedV1, 
    DerivedV2, 
    void(*)(
      const Eigen::MatrixBase< decltype(std::declval< const Eigen::MatrixBase<DerivedV1> &>().row(0)) > &, 
      Eigen::MatrixBase< decltype(std::declval< Eigen::MatrixBase<DerivedV2> &>().row(0)) > const &
    )
    >(V1, V2, callback) ;
}

int main() {
  Eigen::Matrix3f m1 ;
  m1.setRandom() ;

  Eigen::Matrix3f m2 ;
  m2.setRandom() ;

  std::cout << "== random m1 ==" << std::endl << m1 << std::endl ;
  std::cout << "== random m2 ==" << std::endl << m2 << std::endl ;

  reference(m1, m2) ;

  std::cout << "== reference behaviour ==" << std::endl << m2 << std::endl ;

  m2.setRandom() ;

  std::cout << "== random m2 ==" << std::endl << m2 << std::endl ;

  generic(m1, m2, copy) ;
  generic_const(m1, m2, copy) ;

  std::cout << "== final m2 ==" << std::endl << m2 << std::endl ;

  return 0 ;
}

1 Ответ

0 голосов
/ 13 сентября 2018

Чтобы справиться с перегрузками, передайте функтор вместо функции, например:

auto copy_functor = [](auto&& source, auto&& dest){ return copy(source, dest); }

generic(m1, m2, copy_functor);
generic_const(m1, m2, copy_functor);
...