C++ 静态库中带有外部模板的未定义符号

C++ 静态库中带有外部模板的未定义符号,c++,templates,extern,c++14,C++,Templates,Extern,C++14,据我所知,新的外部模板功能可以加快编译和链接时间。我试图在一个(静态)库中使用它,据我所知,它应该可以工作,因为它明确提到了库 我所拥有的是一个头文件,其中包含的内容与 template <typename T> class Foo { // Definitions of the methods }; extern template class Foo<int>; 模板 福班{ //方法的定义 }; 外部模板类Foo; 和一个实现文件 #include "Foo

据我所知,新的外部模板功能可以加快编译和链接时间。我试图在一个(静态)库中使用它,据我所知,它应该可以工作,因为它明确提到了库

我所拥有的是一个头文件,其中包含的内容与

template <typename T>
class Foo {
  // Definitions of the methods
};

extern template class Foo<int>;
模板
福班{
//方法的定义
};
外部模板类Foo;
和一个实现文件

#include "Foo.hpp"
template class Foo<int>;
#包括“Foo.hpp”
模板类Foo;
它们用于构建一个静态库
libfoo
,然后链接到相应的单元测试
FooTest
。然后,链接为测试中对Foo对象调用的每个方法提供了未定义的符号错误


我做错了什么?

使用您的github代码,我可以用GCC 5.0或Clang 3.4复制它,但不能用Clang 3.6(从svn构建)复制它

当它失败时,
Foo.cpp.o
不包含
qux::Foo::Foo(int const&)的定义

$nm-cfoo.cpp.o
uqux::Foo::Foo(int const&)
0000000000000000 W qux::Foo::Foo()
uqux::Foo::Foo(int const&)
0000000000000000 W qux::Foo::Foo()
0000000000000000 W qux::Foo::运算符[](无符号长)常量
0000000000000000 W标准::数组::运算符[](无符号长)常量
0000000000000000 W std::_数组_特征::_S_ref(int const(&)[2],无符号长)
但使用Clang3.6,该符号在

$ nm -C Foo.cpp.o 
0000000000000000 W qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
0000000000000000 W qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
0000000000000000 n qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 n qux::Foo<int, 2ul>::Foo()
0000000000000000 W qux::Foo<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::array<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::__array_traits<int, 2ul>::_S_ref(int const (&) [2], unsigned long)
0000000000000000 W std::array<int, 2ul>::end()
0000000000000000 W std::array<int, 2ul>::data()
0000000000000000 W std::array<int, 2ul>::begin()
0000000000000000 W int* std::__addressof<int>(int&)
$nm-cfoo.cpp.o
0000000000000000 W qux::Foo::Foo(int const&)
0000000000000000 W qux::Foo::Foo()
0000000000000000 W qux::Foo::Foo(int const&)
0000000000000000 W qux::Foo::Foo()
0000000000000000 n qux::Foo::Foo(int const&)
0000000000000000 n qux::Foo::Foo()
0000000000000000 W qux::Foo::运算符[](无符号长)常量
0000000000000000 W标准::数组::运算符[](无符号长)常量
0000000000000000 W std::_数组_特征::_S_ref(int const(&)[2],无符号长)
0000000000000000 W标准::数组::结束()
0000000000000000 W标准::数组::数据()
0000000000000000 W标准::数组::开始()
0000000000000000 W int*std:uu地址(int&)
我不确定问题出在哪里,可能是现在已经修复的Clang中的一个bug,但奇怪的是GCC也有相同的bug


导致问题的函数使用C++14的宽松constexpr规则(在constexpr函数中循环),因此我认为这是编译器实现该新功能时的一个错误。

您如何链接到库?链接顺序很重要,请确保您的
-l
选项位于依赖它的文件之后。我使用的是CMake,但手动链接并将库作为最后一个参数不会改变任何内容。我的命令是
clang++-std=c++-1y-stdlib=libc++-I.././include-L-DCATCH\u CONFIG\u MAIN.././test/FooTest.cpp libfood.a
,在
libfood.a
前面加上
-L
(CMake的命令稍微复杂一些,但基本上是这样做的)。(不太可能是问题的原因,但应该是
-lfood
而不是
-llibfood.a
)很抱歉,我输入错误。我最后尝试了
-lfood
libfood.a
。我无法使用clang或GCC重现您的问题,因此您一定在做问题中未显示的事情。请使用显示问题的命令更新问题(您应该能够在不使用Catch的情况下生成一个只有几行长的简化FooTest.cpp,并向
Foo
添加一个或两个成员函数以演示该问题)。包括编译和链接命令,以及完整的错误。有趣。您不会碰巧在Clang 3.5(当前稳定版本)中测试过这一点)还有,是吗?我希望避免同时构建3.5和HEAD,因为这在我的机器上需要花费很长时间。更新:幸运的是我找到了edge case。感谢您的帮助!不,我没有3.5版本,抱歉。好的,请使用clang++-3.5(最新版本可通过自制获得)再试一次,错误似乎已经修复。现在我在构建过程中遇到了叮当作响的断言失败,但这些与这里的问题无关。再次感谢您帮助我诊断问题!
$ nm -C Foo.cpp.o 
0000000000000000 W qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
0000000000000000 W qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
0000000000000000 n qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 n qux::Foo<int, 2ul>::Foo()
0000000000000000 W qux::Foo<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::array<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::__array_traits<int, 2ul>::_S_ref(int const (&) [2], unsigned long)
0000000000000000 W std::array<int, 2ul>::end()
0000000000000000 W std::array<int, 2ul>::data()
0000000000000000 W std::array<int, 2ul>::begin()
0000000000000000 W int* std::__addressof<int>(int&)