对内联朋友的未定义引用
undefined reference to inline friend
为什么获取内联好友的地址不会导致生成代码。这适用于常规内联函数。声明是否与内联朋友不匹配?
#include <iostream>
namespace S
{
template <unsigned N>
class X
{
int i;
friend X operator+(const X& a, const X& b) noexcept
{
(void)a;
(void)b;
return {};
}
};
inline X<256> operator+(const X<256>&, const X<256>&) noexcept;
}
int main()
{
S::X<256> (*ptr)(const S::X<256>& a, const S::X<256>& b) noexcept = &::S::operator+;
std::cout << (void*)ptr << std::endl;
return 0;
}
$ g++ --version
g++ (GCC) 11.2.1 20220401 (Red Hat 11.2.1-10)
$ g++ -std=c++17 test2.cpp
test2.cpp:18:13: warning: inline function ‘S::X<N> S::operator+(const S::X<N>&, const S::X<N>&) [with unsigned int N = 256]’ used but never defined
18 | inline X<N> operator+(const X<N>&, const X<N>&) noexcept;
| ^~~~~~~~
/usr/bin/ld: /tmp/ccoA1Nxj.o: in function `main':
test2.cpp:(.text+0xc): undefined reference to `S::X<256u> S::operator+<256u>(S::X<256u> const&, S::X<256u> const&)'
collect2: error: ld returned 1 exit status
获取重载集的地址时没有 argument-dependent 查找。
所以,函数指针的初始化不需要编译器实例化X<256>
来判断里面是否有operator+
。对于不合格的函数调用,会发生这种情况。
operator+
在 class 之外的声明也不需要任何涉及的类型是完整的。所以那里也没有 X<256>
的隐式实例化。
因此,当获取函数地址时,X<256>
还没有被实例化,所以编译器无法知道函数的friend
定义,这也是未实例化。
最后,函数没有定义,但是通过获取地址是 ODR-used,因此程序是 ill-formed,不需要诊断。
这可以通过在获取地址之前实例化 X<256>
来解决,例如通过在 main
之前写入 static_assert(sizeof(S::X<256>));
以导致隐式实例化或 template S::X<256>;
以导致显式实例化。
为什么获取内联好友的地址不会导致生成代码。这适用于常规内联函数。声明是否与内联朋友不匹配?
#include <iostream>
namespace S
{
template <unsigned N>
class X
{
int i;
friend X operator+(const X& a, const X& b) noexcept
{
(void)a;
(void)b;
return {};
}
};
inline X<256> operator+(const X<256>&, const X<256>&) noexcept;
}
int main()
{
S::X<256> (*ptr)(const S::X<256>& a, const S::X<256>& b) noexcept = &::S::operator+;
std::cout << (void*)ptr << std::endl;
return 0;
}
$ g++ --version
g++ (GCC) 11.2.1 20220401 (Red Hat 11.2.1-10)
$ g++ -std=c++17 test2.cpp
test2.cpp:18:13: warning: inline function ‘S::X<N> S::operator+(const S::X<N>&, const S::X<N>&) [with unsigned int N = 256]’ used but never defined
18 | inline X<N> operator+(const X<N>&, const X<N>&) noexcept;
| ^~~~~~~~
/usr/bin/ld: /tmp/ccoA1Nxj.o: in function `main':
test2.cpp:(.text+0xc): undefined reference to `S::X<256u> S::operator+<256u>(S::X<256u> const&, S::X<256u> const&)'
collect2: error: ld returned 1 exit status
获取重载集的地址时没有 argument-dependent 查找。
所以,函数指针的初始化不需要编译器实例化X<256>
来判断里面是否有operator+
。对于不合格的函数调用,会发生这种情况。
operator+
在 class 之外的声明也不需要任何涉及的类型是完整的。所以那里也没有 X<256>
的隐式实例化。
因此,当获取函数地址时,X<256>
还没有被实例化,所以编译器无法知道函数的friend
定义,这也是未实例化。
最后,函数没有定义,但是通过获取地址是 ODR-used,因此程序是 ill-formed,不需要诊断。
这可以通过在获取地址之前实例化 X<256>
来解决,例如通过在 main
之前写入 static_assert(sizeof(S::X<256>));
以导致隐式实例化或 template S::X<256>;
以导致显式实例化。