Определение глобальной функции в заголовочном файле - как избежать ошибки связывания дублированного символа

У меня есть следующий код в файле только заголовка.

#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 << "]";
}

Я получаю ошибку привязки, если в проекте есть 2 cpp, этот заголовочный файл.

ошибка LNK2005: "class error_code Оператор __cdecl | (класс error_code const &, класс ViTrox:: error_code const &)" (?? U @@YA? AVerror_code @0 @ABV10 @0 @Z) уже определенный в xxx.obj

Я знаю, что могу решить эту проблему, если переместить определение operator<< в файл cpp или в файл DLL.

Однако я просто хотел бы, чтобы они были в заголовочном файле SINGLE. Есть ли какая-либо техника для достижения такой цели? Или я должен отделить это определение от другого файла?

Ответ 1

Используйте ключевое слово inline.

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

Ответ 2

Либо сделайте функцию inline:

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. Он по-прежнему имеет внешнюю связь, но стандарт позволяет внешним встроенным функциям иметь определение в нескольких единицах перевода.

Ответ 4

Определите эту функцию в файле .cpp(не в файле .h)

//yoursource.cpp
#include "yourheader.h"

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