头文件中的全局函数定义 - 如何避免重复符号链接错误

10

我有以下代码放在一个头文件中。

#pragma once

class error_code {
public:
    unsigned __int64 hi;
    unsigned __int64 lo;    
};

std::ostream& operator<< (std::ostream& o, const error_code& e) {
    return o << "[" << e.hi << "," << e.lo << "]";
}

当项目中有两个 cpp 文件包含此头文件时,我会出现链接错误。

错误 LNK2005:“class error_code __cdecl operator|(class error_code const &,class ViTrox::error_code const &)”(??U@@YA?AVerror_code@0@ABV10@0@Z)已在 xxx.obj 中定义

我知道如果将 operator<< 的定义移动到 cpp 文件或 DLL 文件中,可以解决这个问题。

然而,我只想把它们放在一个单一的头文件中。是否有任何技术可以实现这一点?还是必须将定义分开到另一个文件中?


错误信息与你的代码片段不符。 - Hans Passant
4个回答

18

使用 inline 关键字。

inline std::ostream& operator<< (std::ostream& o, const error_code& e) {
    return o << "[" << e.hi << "," << e.lo << "]";
}

2
不是逐字逐句的翻译,但我记得如果你没有使用“inline”,它会违反ODR(如果你使用了“inline”,但有两个或更多不同的函数体,也会违反ODR)。 - Logan Capaldo
3
inline仅仅是告诉编译器的一个提示,有时候它可能不会进行内联。 - Nawaz
4
@Nawaz,是的,出于优化的目的。但在这种情况下,我们利用它来指定链接。 - Logan Capaldo
2
@Logan Capaldo:inline不会影响函数的链接性。默认情况下,内联函数仍具有外部链接性。 - CB Bailey
1
我可以假装在打那个评论时使用了引号吗? - Logan Capaldo
显示剩余7条评论

7

要么将函数设置为内联

inline std::ostream& operator<< (std::ostream& o, const error_code& e) {
    return o << "[" << e.hi << "," << e.lo << "]";
}

或者将其作为模板函数实现:
template<class Ch, class Tr>
std::basic_ostream<Ch,Tr>& operator<< (std::basic_ostream<Ch,Tr>& o,
                                       const error_code& e) {
    return o << "[" << e.hi << "," << e.lo << "]";
}

3
你可以将函数声明为 static。这会指定内部链接,因此链接器不会在其他翻译单元中已经定义了该函数时产生冲突。
或者,正如先前提到的那样,你可以将其声明为 inline。它仍然具有外部链接,但标准允许外部内联函数在多个翻译单元中具有定义。

0
在 .cpp 文件中定义这个函数(而不是在 .h 文件中)。
//yoursource.cpp
#include "yourheader.h"

std::ostream& operator<< (std::ostream& o, const error_code& e) {
    return o << "[" << e.hi << "," << e.lo << "]";
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接