如何在头文件中声明和定义对象,并在几个静态构建的库中使用它?考虑下面的Headerfile,其中我实现了一个名为Logger的类,我打算在我正在开发的几个库中像这样使用这个类:
Utils::Logging::Logger.Display(true) << SOURCEINFO << "An exception occured: " << exp.what() << Utils::Logging::Save;换句话说,我正在尝试实现和使用它,就像使用std::cout一样。如下所示,我尝试了以下方法,每次都失败了:
static Log Logger;的结果是:Severity Code Description Project File Line Suppression State
Error LNK2005 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl Utils::Logging::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Utils::Logging::Log const &)" (??6Logging@Utils@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV23@AEBVLog@01@@Z) already defined in FV.lib(FV.obj) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\AntiSpoofer.lib(AntiSpoofer.obj) 1
Error LNK2001 unresolved external symbol "class Utils::Logging::Log Utils::Logging::Logger" (?Logger@Logging@Utils@@3VLog@12@A) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\FV.lib(FV.obj) 1
Error LNK1120 1 unresolved externals FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\x64\Release\FV_Test_Lib.exe 1 extern inline Log Logger;结果:Severity Code Description Project File Line Suppression State
Error C7526 'Logger': inline variable is undefined FV D:\Codes\fac_ver\cpp\port\LibtorchPort\Dependencies\include\Utility.h 513 extern Log Logger;,结果是:Severity Code Description Project File Line Suppression State
Error LNK2005 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl Utils::Logging::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Utils::Logging::Log const &)" (??6Logging@Utils@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV23@AEBVLog@01@@Z) already defined in FV.lib(FV.obj) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\AntiSpoofer.lib(AntiSpoofer.obj) 1
Error LNK2001 unresolved external symbol "class Utils::Logging::Log Utils::Logging::Logger" (?Logger@Logging@Utils@@3VLog@12@A) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\FV.lib(FV.obj) 1
Error LNK1120 1 unresolved externals FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\x64\Release\FV_Test_Lib.exe 1 在这一点上,我不确定我是在尝试一些不可能的事情,还是我只是做错了。
这是Utility.h
#ifndef UTILITY_H
#define UTILITY_H
/* If we are we on Windows, we want a single define for it.*/
#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__))
#define _WIN32 //for both 32 and 64 bit. use _WIN64 for 64 bit only
#endif // _WIN32
#if defined(__GNUC__) || defined(unix) || defined(__unix__) || defined(__unix)
# define _UNIX
#endif // _UNIX
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <chrono>
#include <iomanip>
#include <type_traits>
#include <typeinfo>
namespace Utils
{
namespace Logging
{
#ifdef _WIN32
#define FUNC_SIG __FUNCSIG__
#endif
#ifdef _UNIX
#define FUNC_SIG __PRETTY_FUNCTION__
#endif
#define SOURCEINFO __FILE__<<":"<<__LINE__<<":"<<FUNC_SIG<<": "
template<typename... Args>
void LogMsg(std::string logFilename = "FVLog.txt", bool display = true, Args... args)
{
std::ofstream logFile;
logFilename = (logFilename == "") ? "FVLog.txt" : logFilename;
logFile.open(logFilename, std::ios::out | std::ios::app);
logFile << DateTime::Now(false);
if (display)
((std::cout << args), ...);
//cpp17 fold-expression:, recursively send each value to be saved in our stream
((logFile << args), ...);
}
enum class Mode
{
Save = 0,
Load = 1
};
static constexpr Mode Save = Mode::Save;
class Log
{
private:
std::stringstream stream;
bool isNew = true;
bool displayResults=false;
bool benchMode = false;
public:
template <typename T>
Log& operator<<(const T& value)
{
if (isNew)
{
stream << DateTime::Now(false) << " ";
isNew = false;
}
if constexpr (std::is_same<T, Logging::Mode>::value)
{
if (value == Mode::Save)
Save();
if (displayResults)
std::cout << std::endl;;
}
else
{
stream << value;
}
if (displayResults)
std::cout << stream.str();
return *this;
}
void Save(std::string logFilename= "FVLog.txt")
{
isNew = true;
if (benchMode)
return;
std::ofstream logFile;
logFilename = (logFilename == "") ? "FVLog.txt" : logFilename;
logFile.open(logFilename, std::ios::out | std::ios::app);
logFile << this->Get() << std::endl;
this->stream.clear();
this->stream.str("");
logFile.close();
}
Log& Display(bool showOutput, bool benchMode=false)
{
displayResults = showOutput;
this->benchMode = benchMode;
return *this;
}
std::string Get() const
{
return this->stream.str();
}
friend std::ostream& operator<<(std::ostream& os, const Log& log);
};
std::ostream& operator<<(std::ostream& os, const Log& log)
{
os << log.Get();
return os;
}
extern Log Logger;
}
}
#endif // !UTILITY_H我在这里错过了什么?
更新
跟着@Peter的回答。我做了第一个选项,即在头文件中我们有Log Logger;,然后在其中一个库中,例如FV.cpp,我做了:
#include <Utility.h>
...
Utils::Logging::Log Logger;如果出现以下错误,这将失败:
Severity Code Description Project File Line Suppression State
Error LNK2005 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl Utils::Logging::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Utils::Logging::Log const &)" (??6Logging@Utils@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV23@AEBVLog@01@@Z) already defined in FV.lib(FV.obj) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\AntiSpoofer.lib(AntiSpoofer.obj) 1
Error LNK2001 unresolved external symbol "class Utils::Logging::Log Utils::Logging::Logger" (?Logger@Logging@Utils@@3VLog@12@A) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\FV.lib(FV.obj) 1
Error LNK1120 1 unresolved externals FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\x64\Release\FV_Test_Lib.exe 1

更新2
下面是一个最小可还原的示例:https://gofile.io/d/eJeADp
发布于 2020-09-30 09:16:36
记录器需要在.cpp文件中的某个地方实例化。
Log Logger;仅仅宣布这是不够的。
#include "logger.h"
Utils::Logging::Log Logger;
void Test() {
Logger << 42;
}发布于 2020-09-30 09:25:13
可以多次声明全局对象,但必须在整个程序中精确地定义一次。问题是头部可以由多个编译单元(也称为源文件)包含,这意味着头文件中的定义可能导致多个定义。
有几个选择。我会给你两个。
选项1-如果对象位于文件范围内(在任何函数之外,而不是类成员),则可以这样做。
extern Log Logger;在头文件中,并将该头包含在多个编译单元中。(如果头包含定义(例如,类定义),则通常需要包含保护以防止单个编译单元多次包含标头)。
然后,在整个项目中的单个编译单元中,包含该标头以获取声明,然后定义它。
#include "header.h" // for the definition of Log and the declaration extern Log Logger
Log Logger; // definition of Logger选项2-如果对象是类的静态成员,则在类定义中(在标头内)执行
static Log Logger;然后在一个单独的编译单元中
#include "header.h" // for the definition of the class or struct
Log WhateverClass::Logger;https://stackoverflow.com/questions/64134370
复制相似问题