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

C++ 链接器未拾取模板运算符重载,c++,c++11,linker,c++20,C++,C++11,Linker,C++20,我有一个最小的工作示例(我特意在这里使用cstdio,以保持nm输出可读性): 它失败了 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_6

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

它失败了

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)
并使用
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&)
main.o:00000000000000 60 T Foo::Foo(int)
main.o:00000000000000 90 T Foo::Foo(int)
main.o:U运算符==(Foo常量&,Foo常量&)
干管:0000000000000000吨干管
main.o:U\U printf
foo.o:00000000000000 20吨foo::foo(int)
foo.o:0000000000000000 T foo::foo(int)
foo.o:00000000000000 50 T布尔运算符==(foo常量和,foo常量和)
尽管这两个签名对我来说是兼容的,但当我尝试链接时,它失败了:

$ 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
$ld-lc foo.o main.o2>&1|c++过滤器
架构x86_64的未定义符号:
“运算符==(Foo const&,Foo const&)”,引用自:
_主音中的主音
ld:未找到架构x86_64的符号(短)

为什么??我怎样才能解决这个问题?

好的,问这个问题有橡皮鸭效应。编译器抱怨,因为它期望
friend bool operator==
是一个普通的非模板函数,而它不是-这可以从
main.o
期望
operator==
看到,而
foo.o
导出
operator=

为了告诉编译器操作符本身就是一个模板(在其他地方实现),我必须将我的
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);
};

这使得所有链接都正确。

Huh,这是一个gcc警告clang不正确的例子。我可以发誓我以前遇到过这个问题,gcc警告过我(
警告:友元声明'bool operator==(const Foo&,const Foo&)'声明了一个非模板函数[-Wnon-template-friend]
和just-Wall)
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)
clang --std=c++2a -c main.cpp
clang --std=c++2a -c foo.cpp
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
#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);
};
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&)