Eigen中unaryExpr调用同结构体成员函数编译失败问题
问题:Eigen unaryExpr调用类成员函数编译失败
问题重现
当sigmoid为全局函数时,代码可正常编译运行:
#include <Eigen/Dense> #include <Eigen/Sparse> #include <Eigen/Core> #include <iostream> using Eigen::MatrixXd, std::cout, std::cin; double sigmoid(double x) { return 1.0 / (1.0 + exp(-x)); } struct Network { public: MatrixXd sigmoid_matrix(MatrixXd z) { return z.unaryExpr(&sigmoid); } }; int main() { Network net; Eigen::MatrixXd m(1, 4); m << 1, 2, 3, 4; cout << net.sigmoid_matrix(m); }
但将sigmoid移入Network结构体作为非静态成员函数后,编译失败:
#include <Eigen/Dense> #include <Eigen/Sparse> #include <Eigen/Core> #include <iostream> using Eigen::MatrixXd, std::cout, std::cin; struct Network { public: double sigmoid(double x) { return 1.0 / (1.0 + exp(-x)); } MatrixXd sigmoid_matrix(MatrixXd z) { return z.unaryExpr(&Network::sigmoid); } }; int main() { Network net; Eigen::MatrixXd m(1, 4); m << 1, 2, 3, 4; cout << net.sigmoid_matrix(m); }
核心报错信息
D:/Projects/c++/eigen/Eigen/src/Core/util/Meta.h:272:61: error: no type named 'type' in 'struct std::invoke_result<double (Network::*)(double), const double&>' 272 | typedef typename std::invoke_result<F, ArgTypes...>::type type1; | ^~~~~ D:/Projects/c++/eigen/Eigen/src/Core/util/Meta.h:273:31: error: no type named 'type' in 'struct std::invoke_result<double (Network::*)(double), const double&>' 273 | typedef remove_all_t<type1> type; | ^~~~
完整报错信息
PS D:\Projects\c++\NeuralNetwrokNumbers> g++ -I D:/Projects/c++/eigen network.cpp -o network.exe In file included from D:/Projects/c++/eigen/Eigen/Core:169, from D:/Projects/c++/eigen/Eigen/Dense:1, from network.cpp:1: D:/Projects/c++/eigen/Eigen/src/Core/util/Meta.h: In instantiation of 'struct Eigen::internal::result_of<double (Network::*(const double&))(double)>': D:/Projects/c++/eigen/Eigen/src/Core/CwiseUnaryOp.h:26:28: required from 'struct Eigen::internal::traits<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >' D:/Projects/c++/eigen/Eigen/src/Core/CwiseUnaryOp.h:97:7: required from 'class Eigen::CwiseUnaryOpImpl<double (Network::*)(double), const Eigen::Matrix<double, -1, -1>, Eigen::Dense>' D:/Projects/c++/eigen/Eigen/src/Core/CwiseUnaryOp.h:58:7: required from 'class Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> >' network.cpp:19:27: required from here D:/Projects/c++/eigen/Eigen/src/Core/util/Meta.h:272:61: error: no type named 'type' in 'struct std::invoke_result<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> >' D:/Projects/c++/eigen/Eigen/src/Core/util/Meta.h:273:31: error: no type named 'type' in 'struct std::invoke_result<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> >' In file included from D:/Projects/c++/eigen/Eigen/Core:292: D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h: In instantiation of 'class Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >': D:/Projects/c++/eigen/Eigen/src/Core/MatrixBase.h:51:34: required from 'class Eigen::MatrixBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >' D:/Projects/c++/eigen/Eigen/src/Core/CwiseUnaryOp.h:97:7: required from 'class Eigen::CwiseUnaryOpImpl<double (Network::*)(double), const Eigen::Matrix<double, -1, -1>, Eigen::Dense>' D:/Projects/c++/eigen/Eigen/src/Core/CwiseUnaryOp.h:58:7: required from 'class Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> >' network.cpp:19:27: required from here D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:79:17: error: 'coeff' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 79 | using Base::coeff; | ^~~~~ D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:80:17: error: 'coeffByOuterInner' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 80 | using Base::coeffByOuterInner; | ^~~~~~~~~~~~~~~~~ D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:81:26: error: 'operator()' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 81 | using Base::operator(); | ^ D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:82:26: error: 'operator[]' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 82 | using Base::operator[]; | ^ D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:83:17: error: 'x' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 83 | using Base::x; | ^ D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:84:17: error: 'y' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 84 | using Base::y; | ^ D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:85:17: error: 'z' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 85 | using Base::z; | ^ D:/Projects/c++/eigen/Eigen/src/Core/DenseBase.h:86:17: error: 'w' has not been declared in 'Eigen::DenseBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 86 | using Base::w; | ^ In file included from D:/Projects/c++/eigen/Eigen/Core:293: D:/Projects/c++/eigen/Eigen/src/Core/MatrixBase.h: In instantiation of 'class Eigen::MatrixBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >': D:/Projects/c++/eigen/Eigen/src/Core/CwiseUnaryOp.h:97:7: required from 'class Eigen::CwiseUnaryOpImpl<double (Network::*)(double), const Eigen::Matrix<double, -1, -1>, Eigen::Dense>' D:/Projects/c++/eigen/Eigen/src/Core/CwiseUnaryOp.h:58:7: required from 'class Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> >' network.cpp:19:27: required from here D:/Projects/c++/eigen/Eigen/src/Core/MatrixBase.h:78:17: error: 'coeff' has not been declared in 'Eigen::MatrixBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 78 | using Base::coeff; | ^~~~~ D:/Projects/c++/eigen/Eigen/src/Core/MatrixBase.h:81:17: error: 'eval' has not been declared in 'Eigen::MatrixBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 81 | using Base::eval; | ^~~~ D:/Projects/c++/eigen/Eigen/src/Core/MatrixBase.h:82:25: error: 'operator-' has not been declared in 'Eigen::MatrixBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 82 | using Base::operator-; | ^ D:/Projects/c++/eigen/Eigen/src/Core/MatrixBase.h:85:25: error: 'operator*=' has not been declared in 'Eigen::MatrixBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 85 | using Base::operator*=; | ^~ D:/Projects/c++/eigen/Eigen/src/Core/MatrixBase.h:86:25: error: 'operator/=' has not been declared in 'Eigen::MatrixBase<Eigen::CwiseUnaryOp<double (Network::*)(double), const Eigen::Matrix<double, -1, -1> > >::Base' 86 | using Base::operator/=; | ^~
编译失败原因
非静态成员函数的调用依赖于类的实例对象:C++中,非静态成员函数会隐式接收一个this指针作为第一个参数,用来指向当前调用的类实例。而Eigen的unaryExpr方法只会向传入的可调用对象传递矩阵的单个元素,无法提供成员函数所需的this指针,导致参数不匹配。
核心报错中的std::invoke_result错误,本质就是编译器无法用const double&(矩阵元素)去调用需要Network*+double参数的成员函数double (Network::*)(double),因此无法推导返回类型。后续的一系列报错都是这个核心问题引发的连锁反应。
解决方案
方案1:将sigmoid改为静态成员函数
静态成员函数不依赖类实例,不需要this指针,可以直接作为函数指针传递给unaryExpr:
#include <Eigen/Dense> #include <iostream> using Eigen::MatrixXd, std::cout; struct Network { public: static double sigmoid(double x) { // 改为static return 1.0 / (1.0 + exp(-x)); } MatrixXd sigmoid_matrix(MatrixXd z) { return z.unaryExpr(&Network::sigmoid); // 直接传递静态成员函数指针 } }; int main() { Network net; Eigen::MatrixXd m(1, 4); m << 1, 2, 3, 4; cout << net.sigmoid_matrix(m); }
方案2:使用lambda表达式捕获this
通过lambda捕获当前对象的this指针,在lambda内部调用成员函数,lambda可以直接被unaryExpr接受:
#include <Eigen/Dense> #include <iostream> using Eigen::MatrixXd, std::cout; struct Network { public: double sigmoid(double x) { return 1.0 / (1.0 + exp(-x)); } MatrixXd sigmoid_matrix(MatrixXd z) { // 捕获this,在lambda中调用成员函数 return z.unaryExpr([this](double x) { return this->sigmoid(x); }); } }; int main() { Network net; Eigen::MatrixXd m(1, 4); m << 1, 2, 3, 4; cout << net.sigmoid_matrix(m); }
方案3:使用std::bind绑定this指针
用std::bind将this指针和成员函数绑定,生成一个适配后的可调用对象:
#include <Eigen/Dense> #include <iostream> #include <functional> // 需要包含bind的头文件 using Eigen::MatrixXd, std::cout, std::bind; struct Network { public: double sigmoid(double x) { return 1.0 / (1.0 + exp(-x)); } MatrixXd sigmoid_matrix(MatrixXd z) { // 绑定this指针到成员函数 return z.unaryExpr(bind(&Network::sigmoid, this, std::placeholders::_1)); } }; int main() { Network net; Eigen::MatrixXd m(1, 4); m << 1, 2, 3, 4; cout << net.sigmoid_matrix(m); }
内容的提问来源于stack exchange,提问作者Fisteshak
相关产品推荐
相关产品推荐

