【问题标题】:Linker error when using template class with a reference non-type template parameter使用带有引用非类型模板参数的模板类时出现链接器错误
【发布时间】:2019-01-08 21:08:46
【问题描述】:

我正在开发一个 C++ 库,我需要在其中向用户提供类模板。

这个类的模板参数是一个引用。但是,我收到链接器错误。这是一个最小的测试用例:

test.hh

#ifndef TEST_HH_
#define TEST_HH_

template <double const& val>
struct A{};

constexpr double zero = 0.;

A<zero> foo();

#endif // TEST_HH_

test.cpp

#include "test.hh"

A<zero> foo(){ return A<zero>(); }

main.cpp

#include "test.hh"

int main()
{
    foo();
}

编译这段代码时,我收到警告:

'A<zero> foo()' used but never defined

随后出现链接器错误:

undefined reference to foo()

我试图用 int 替换双精度:

template <int val>
struct A{};

它链接了(当传递 int 作为参数 ofc 时),但我真的需要一个 double

当模板类涉及链接错误时,我也尝试了一个常见的解决方案,我在test.hh 中实现了foo() 函数而不是test.cpp,但我想避免只将所有代码放在标题中。

【问题讨论】:

    标签: c++ templates linker c++14 non-type


    【解决方案1】:

    很高兴这没有链接!可能会更糟...

    问题基本上是test.cppmain.cpp 都有名为::zero不同 对象。这是一个 ODR 违规 - 您对该变量有多个定义,并且您最终得到 A&lt;zero&gt; 在技术上是不同的类型,因为 A 的模板参数 val 是对不同翻译单元中不同对象的引用。

    希望这个解释能说明为什么A&lt;int&gt; 可以正常工作。

    在 C++17 中,您希望:

    inline constexpr double zero = 0.;
    

    在 C++14 中,您要么需要在其中一个翻译单元中添加定义,要么做一些其他类型的魔法,比如让 ::zero 本身成为对某个静态模板变量或其他巫术的引用。

    【讨论】:

    • 天哪,它有效!让我们迁移到 cpp 17 :) 非常感谢。我认为全局范围或命名空间中的变量默认具有外部链接。 (是的,这解释了 int,因为我没有声明任何变量,所以我在两个文件中都做了 A,所以值是相同的)。
    • @Baxlan 它确实有外部链接 - 这不是问题。
    • 外部链接不是意味着变量在所有翻译单元中只有一个定义吗?
    • @Baxlan 呃,对不起,我弄错了。命名空间范围是内部链接。它添加了 inline 使其成为外部。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多