使用LLVM-Clang隐式实例化私有C ++模板的链接器错误

时间:2014-07-03 12:07:12

标签: c++ templates visual-c++ llvm-clang

免责声明:我知道模板通常在头文件中实现。请仔细阅读。

我遇到了与C ++模板相关的问题。我的代码在Windows下使用MSVC构建,但在Mac OSX下不支持LLVM-Clang,但我不确定哪一个是错误的。

这是一个简单的测试用例,由三个源文件组成:

  • 的main.cpp

    #include "templ.h"
    
    int main()
    {
       templ(1);
       return 0;
    }
    
  • templ.h

    template<typename T>
    T templ(const T&);
    
  • templ.cpp

    #include "templ.h"
    
    template<typename T>
    T templ(const T& t)
    {
       return t;
    }
    
    //explicit instantiation
    template int templ(const int&);
    
    //implicit instantiation
    void f()
    {
       templ(1);
    }
    

如您所见,我希望函数模板的实现是私有的(即隐藏在.cpp文件中)。为此,我必须在与其定义相同的翻译单元中实例化我的模板。在上面的例子中,我只实例化templ<int>。 AFAIK,这是不寻常的,但完美的C ++。

原样,此代码与两个编译器一起构建。但是,如果我注释掉显式实例化并且只保留隐式实例化,则编译器的行为会有所不同。 MSVC成功构建,但LLVM-Clang因以下链接器错误而失败:

Undefined symbols for architecture x86_64:
  "int templ<int>(int const&)", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture x86_64

此外,只有在启用优化时才会出现该错误(例如-02)。

标准对此有何评价?这是LLVM-Clang的已知行为/错误吗?

我的LLVM-Clang版本是:

Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix

很抱歉,如果这是重复的话。选择正确的关键字非常困难。

1 个答案:

答案 0 :(得分:6)

这是正常的和预期的。

  

14个模板
  6函数模板,类模板的成员函数,变量模板或类模板的静态数据成员应在每个隐式实例化的转换单元中定义(14.7.1),除非明确实例化相应的特化(14.7) .2)在某些翻译单位;无需诊断。

适用于您的情况,这意味着当删除templ的显式实例化时,编译器可以

  1. 通常由于同一TU中的隐式实例化而生成实例化;或
  2. 内联对templ的调用,不生成任何外部可用的实体。
  3. 允许符合条件的实施行为。如果确定某处有明确的实例化,则要么生成有效的对象代码。如果你没有,你可能会或可能不会收到错误,这是你自己的错。