链接器未拾取模板运算符重载

问题描述 投票:0回答:1

我有这个最小的工作示例(在这里我故意使用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个回答
0
投票

好,问这个问题有橡皮鸭的作用。编译器会抱怨,因为它希望friend bool operator==是一个普通的非模板函数,而事实并非如此-可以从main.o期望operator==看出,而foo.o导出operator==<int>

为了告诉编译器该运算符本身就是一个模板(在其他地方实现),我必须按以下方式更改我的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&)

哪个都可以正确链接。

© www.soinside.com 2019 - 2024. All rights reserved.