【问题标题】:Template operator overload is not picked up by linker链接器未拾取模板运算符重载
【发布时间】:2020-05-30 21:32:44
【问题描述】:

我有这个最小的工作示例(我故意在这里使用cstdio 以保持nm 输出可读):

// main.cpp
#include "cstdio"
#include "foo.hpp"

int main() {
    Foo<int> foo{42};
    Foo<int> bar{42};

    bool b = foo == bar;
    printf("%d\n", b);

    return 0;
}
// foo.hpp
#pragma once

template<typename T>
struct Foo {
    Foo(T foo_) : foo{foo_} {}

    T foo;

    friend bool operator==(const Foo<T> &lhs, const Foo<T> &rhs);
};
// foo.cpp
#include "foo.hpp"

template<typename T>
bool operator==(const Foo<T> &lhs, const Foo<T> &rhs) {
    return false;
}

template struct Foo<int>;
template bool operator==(const Foo<int> &lhs, const Foo<int> &rhs);

我是这样构建的:

clang --std=c++2a -lstdc++ main.cpp foo.cpp

失败了

Undefined symbols for architecture x86_64:
  "operator==(Foo<int> const&, Foo<int> const&)", referenced from:
      _main in main-3d7fff.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

尽管我明确实例化了operator== 模板。

我已经分别重建了每个文件:

clang --std=c++2a -c main.cpp
clang --std=c++2a -c foo.cpp

并通过nm 进行了探索:

main.o: 0000000000000060 T Foo<int>::Foo(int)
main.o: 0000000000000090 T Foo<int>::Foo(int)
main.o:                  U operator==(Foo<int> const&, Foo<int> const&)
main.o: 0000000000000000 T _main
main.o:                  U _printf
foo.o: 0000000000000020 T Foo<int>::Foo(int)
foo.o: 0000000000000000 T Foo<int>::Foo(int)
foo.o: 0000000000000050 T bool operator==<int>(Foo<int> const&, Foo<int> const&)

尽管这两个签名对我来说看起来兼容,但当我尝试链接它时,它失败了:

$ ld -lc foo.o main.o 2>&1 | c++filt
Undefined symbols for architecture x86_64:
  "operator==(Foo<int> const&, Foo<int> const&)", referenced from:
      _main in main.o
ld: symbol(short) not found for architecture x86_64

为什么?我该如何解决这个问题?

【问题讨论】:

    标签: c++ c++11 linker c++20


    【解决方案1】:

    好的,问这个问题有橡皮鸭效应。编译器投诉,因为它期望 friend bool operator== 是一个普通的、非模板函数,但它不是 - 这可以通过 main.o 期望 operator== 看到,而 foo.o 导出 operator==&lt;int&gt;

    为了告诉编译器操作符本身就是一个模板(在其他地方实现),我不得不更改我的foo.hpp 如下:

    #pragma once
    
    // forward declaration of Foo to use in forward declaration of operator== template
    template<typename T> struct Foo;
    // forward declaration of operator== template
    template<typename T> bool operator==(const Foo<T> &lhs, const Foo<T> &rhs);
    
    template<typename T>
    struct Foo {
        Foo(T foo_) : foo{foo_} {}
    
        T foo;
    
        // indicate operator== is some template
        friend bool operator==<>(const Foo<T> &lhs, const Foo<T> &rhs);
    };
    

    现在,nm 产生预期的输出:

    foo.o: 0000000000000050 T bool operator==<int>(Foo<int> const&, Foo<int> const&)
    main.o:                  U bool operator==<int>(Foo<int> const&, Foo<int> const&)
    

    这使得所有链接都正确。

    【讨论】:

    • 嗯,这是 gcc 发出 clang 没有的警告的一种情况。我本可以发誓我以前遇到过这种情况,gcc 警告我(warning: friend declaration 'bool operator==(const Foo&lt;T&gt;&amp;, const Foo&lt;T&gt;&amp;)' declares a non-template function [-Wnon-template-friend] 只需 -Wall)
    猜你喜欢
    • 2011-03-01
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 2013-03-05
    • 1970-01-01
    • 2015-01-28
    • 1970-01-01
    相关资源
    最近更新 更多