来自 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 &lt;vector&gt; 或匿名enum 定义会触发问题。编译后的f&lt;2&gt; 中的类型名称很可能是(Eigen::._83),因此不匹配。

恐怕我不是编译器内部或 C++ 标准深度方面的专家,不能说这是 GCC 编译器中的错误,还是仅仅是解释不同的问题。

另一个涉及修改特征码并且似乎有效的解决方案是为Constants.h 中的enum 提供一个名称,该名称定义AutoAlignRowMajorColMajor,因为问题在于使用匿名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

gtest:架构 x86_64 的未定义符号与 clang++ 和 std::vector 错误

带有 Catch 库的未解析外部符号