来自 GCC 的未定义参考错误使用带有 std::vector 和特征矩阵的模板?
Posted
技术标签:
【中文标题】来自 GCC 的未定义参考错误使用带有 std::vector 和特征矩阵的模板?【英文标题】:Undefined reference error from GCC using a template with a std::vector and an Eigen Matrix? 【发布时间】:2014-07-14 06:52:26 【问题描述】:我在使用 GCC 编译以下代码时遇到未定义的引用错误 4.7.2 x86_64-suse-linux下的20130108通过命令:
g++ main.cpp func.cpp -I/path/to/eigenlibrary/eigen_3.2.1
错误信息如下:
main.cpp:(.text+0x1d): undefined reference to `void f<2>(std::vector<Eigen::Matrix<double, 2, 2,
((Eigen::._84)0)|((((2)==(1))&&((2)!=(1)))?
((Eigen::._84)1) : ((((2)==(1))&&((2)!=(1)))?((Eigen::._84)0) : ((Eigen::._84)0))), 2, 2>,
std::allocator<Eigen::Matrix<double, 2, 2, ((Eigen::._84)0)|((((2)==(1))&&((2)!=(1)))?
((Eigen::._84)1) : ((((2)==(1))&&((2)!=(1)))?((Eigen::._84)0) : ((Eigen::._84)0))), 2, 2> > >&)'
请注意,这与模板实现与头文件分离这一事实无关,因为没有模板函数的(通用)实现,而只是模板特化。模板特化的实现不能放到头文件中,因为这样会产生多个定义错误。
这里的另一个奇怪的事情是,如果我更改 main.cpp 中前两个标题包含的顺序(特征/密集和向量),则不会发生错误。我对此一无所知,任何超出“只需更改标题包含的顺序”的帮助将不胜感激。
main.cpp:
#include <vector>
#include <Eigen/Dense>
//error does not occur once I change order of header inclusion like so:
//#include <Eigen/Dense>
//#include <vector>
#include "func.h"
int main()
std::vector<Eigen::Matrix<double, 2, 2> > m;
f<2>(m);
func.h
#ifndef FUNC_H
#define FUNC_H
#include <Eigen/Dense>
#include <vector>
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N> >& m);
template <> void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m);
#endif
func.cpp
#include "func.h"
#include <vector>
template <>
void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m)
【问题讨论】:
在再次询问之前,您介意删除您的old question吗? 已删除,抱歉。 @πάνταῥεῖ 公平地说,这个问题问的是完全不同的东西。 @rubenvb 这就是为什么我没有关闭投票认为这是重复的。不过,这些问题(曾经)非常相似。 @πάνταῥεῖ 但是为什么要求删除该问题?它已被标记为重复。这不是删除问题的理由...... 【参考方案1】:在func.h
中,您的模板特化声明应为:
template <> void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m);
所以,在整个过程中填写 N=2
,就像在 func.cpp
中的定义一样。
请注意,如果您将 inline
添加到定义中,您应该能够在 func.h
中定义您的模板特化。
我可以在 Arch Linux 上使用 GCC 4.6.4、4.7.4、4.8.2、4.9.0,但不能使用 Clang 3.4.2 重现故障:
$ echo $'func.h\n---'; cat func.h; echo $'---\nfunc.c++\n---'; cat func.c++; echo $'---\nmain.c++\n---'; cat main.c++; g++-4.6 -I/usr/include/eigen3 main.c++ func.c++; ./a.out
func.h
---
#ifndef FUNC_H
#define FUNC_H
#include <Eigen/Dense>
#include <vector>
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N> >& m);
template <> void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m);
#endif
---
func.c++
---
#include "func.h"
#include <vector>
template <>
void f<2>(std::vector<Eigen::Matrix<double, 2, 2> >& m)
---
main.c++
---
#include <vector>
#include <Eigen/Dense>
//error does not occur once I change order of header inclusion like so:
//#include <Eigen/Dense>
//#include <vector>
#include "func.h"
int main()
std::vector<Eigen::Matrix<double, 2, 2> > m;
f<2>(m);
我强烈建议就此联系 Eigen 开发人员。
【讨论】:
当然是的,我打错了,问题还是一样 @user 使它为我编译/链接没有错误。 你使用的是同一个编译器吗?它使用 intel 编译器在我的机器上编译得很好,但不是 gcc @user 那么它可能是一个编译器错误。您可以尝试更新版本的 GCC 或 Clang 吗? GCC 4.9。我会看看我是否能获得 GCC 4.7.3 和其他版本。【参考方案2】:我知道这是一个老问题,但我们在不同的环境中遇到了同样的问题,我想我会分享我们的解决方案。
至少对于 GCC 4.8.2-19ubuntu1,未解决的链接错误的解决方案是替换 func.h 中的以下内容
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N> >& m);
与
template <int N>
void f(std::vector<Eigen::Matrix<double, N, N, 0> >& m);
请注意,第四个模板参数显式给出为 0,这是链接器错误中模板函数声明中显示的表达式的结果,
((Eigen::._84)0)|((((2)==(1))&&((2)!=(1)))?
((Eigen::._84)1) : ((((2)==(1))&&((2)!=(1)))?((Eigen::._84)0)
表达式来自第四个模板参数的默认值,在 Eigen ForwardDeclarations.h
文件中给出为
AutoAlign |
( (_Rows==1 && _Cols!=1) ? RowMajor
: (_Cols==1 && _Rows!=1) ? ColMajor
: EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION )
还有另一种方法可以解决 Eigen 代码中的问题,我稍后会提到。
问题的原因似乎是 GCC 编译器延迟了对该表达式的评估,并且该表达式涉及匿名枚举类型,其类型名称在表达式中明确给出(在这种情况下为(Eigen::._84)
)。此外,GCC 编译器似乎使用计数器生成匿名 enum
类型名称,因此类型名称取决于之前出现了多少匿名 enum
类型,这可能因不同的编译单元而异。这就是为什么在包含Eigen/Dense
之前添加#include <vector>
或匿名enum
定义会触发问题。编译后的f<2>
中的类型名称很可能是(Eigen::._83)
,因此不匹配。
恐怕我不是编译器内部或 C++ 标准深度方面的专家,不能说这是 GCC 编译器中的错误,还是仅仅是解释不同的问题。
另一个涉及修改特征码并且似乎有效的解决方案是为Constants.h
中的enum
提供一个名称,该名称定义AutoAlign
、RowMajor
和ColMajor
,因为问题在于使用匿名enum
类型。例如:
/** \ingroup enums
* Enum containing possible values for the \p _Options template parameter of
* Matrix, Array and BandMatrix. */
enum MatrixOptionsType
ColMajor = 0,
RowMajor = 0x1,
AutoAlign = 0,
DontAlign = 0x2
;
不过,我不确定 Eigen 开发人员是否可以接受。
【讨论】:
以上是关于来自 GCC 的未定义参考错误使用带有 std::vector 和特征矩阵的模板?的主要内容,如果未能解决你的问题,请参考以下文章
gcc 和 pthreads 的未定义引用错误 _dl_stack_flags
std::declval() 在 GCC 中触发带有警告的断言错误
使用 ASIO 和 std::thread 制作 C++11 应用程序时对“pthread_create”的未定义引用错误
带有 -fpack-struct 段错误的 gcc std::regex