【问题标题】:Use of std::forward with Eigen::Ref objects将 std::forward 与 Eigen::Ref 对象一起使用
【发布时间】:2021-08-29 08:26:20
【问题描述】:

我有一个函子Foo,定义如下:

struct Foo {
    template <typename _Vector>
    void operator()(const Eigen::Ref<const _Vector>&, const Eigen::Ref<const _Vector>&) {
        /* ... */
    }
};

我想用特征向量、块或 Eigen::Ref 来调用它,_Vector 可以是任何特征向量类型。此实现不起作用,因为您必须完全使用Eigen::Ref&lt;const _Vector&gt; 参数调用它——而不是,例如,使用向量或向量段。我发现的解决方法如下:

struct Foo {
    /* This works, but I'm not sure if it is the most correct solution. */
    template <typename T, typename U>
    void operator()(const T& x, const U& y) {
        Impl<typename T::PlainObject>(x, y);
    }

    /* This doesn't work, but I expected this to be the most correct solution. */
    // template <typename T, typename U>
    // void operator()(T&& x, U&& y) {
    //     Impl<typename T::PlainObject>(std::forward<T>(x), std::forward<U>(y));
    // }

    template <typename _Vector>
    void Impl(const Eigen::Ref<const _Vector>&, const Eigen::Ref<const _Vector>&) {
        /* ... */
    }
};

在这里,我将实现隐藏在函数Impl 中,并使用operator() 捕获每个参数;然后,我从第一个参数(x)的成员类型PlainObject 中推导出正确的_Vector 类型。但是,我希望注释代码更加“正确”,因为它完美地转发了参数,因此Impl 使用它们的方式与它们应该是完全一样的。 此断言是否错误?不幸的是,它失败并出现以下错误:

error: ‘Eigen::Ref<Eigen::Matrix<double, -1, 1> >&’ is not a class, struct, or union type
[build]   390 |         Impl<typename T::PlainObject>(std::forward<T>(x), std::forward<U>(y));
[build]       |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

它声明Eigen::Ref 不是类、结构或联合类型;但它实际上是一个类。 如何解决此错误?

P.S.:我必须承认,我不是 100% 有信心知道何时应该使用 T&amp;&amp;std::forward。我的理解是,它们为您提供的正是您传递的内容,而无需额外的副本或隐式转换。

【问题讨论】:

  • T 是否有一个名为 PlainObject 的 typedef? Impl 是什么?你能把它变成minimal reproducible example吗?
  • @TedLyngmo 我提供的代码已经很少了,只要您可以访问 Eigen 库就可以工作。 PlainObject 是为所有 Eigen 类型定义的成员类型,定义了任何 Eigen 对象的底层类型,无论是块、段、Eigen::Ref 等。
  • 好的,如果有的话,我希望我在答案中输入的内容有效。

标签: c++ templates reference eigen c++20


【解决方案1】:
error: ‘Eigen::Ref<Eigen::Matrix<double, -1, 1> >&’ is not a class, struct, or union type
                                                 ^

您需要std::remove_reference使完美转发版本生效:

#include <type_traits>

template <typename T, typename U>
void operator()(T&& x, U&& y) {
     Impl<typename std::remove_reference_t<T>::PlainObject>(std::forward<T>(x),
                                                            std::forward<U>(y));
}

【讨论】:

  • 谢谢,这确实有效!也许,std::decay_t 可能是一个更好的选择,对吧?另外,您能否以粗体字回答第一个问题,即右值引用的解决方案是否是“正确”的解决方案?
  • 不客气。是的,在某些情况下您可能需要decayDifference between std::decay and std::remove_reference。不过,我认为这并不重要。两个版本都是“正确的”,但这个版本可能更可取,因为它允许完美转发。
猜你喜欢
  • 2012-08-16
  • 2013-06-30
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 2016-07-08
相关资源
最近更新 更多