首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在头文件中导出对象?

如何在头文件中导出对象?
EN

Stack Overflow用户
提问于 2020-09-30 09:09:11
回答 2查看 269关注 0票数 0

如何在头文件中声明和定义对象,并在几个静态构建的库中使用它?考虑下面的Headerfile,其中我实现了一个名为Logger的类,我打算在我正在开发的几个库中像这样使用这个类:

代码语言:javascript
复制
Utils::Logging::Logger.Display(true) << SOURCEINFO << "An exception occured: " << exp.what() << Utils::Logging::Save;

换句话说,我正在尝试实现和使用它,就像使用std::cout一样。如下所示,我尝试了以下方法,每次都失败了:

  1. 尝试static Log Logger;的结果是:

代码语言:javascript
复制
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   

  1. Doing extern inline Log Logger;结果:

代码语言:javascript
复制
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 

  1. 和简单地执行extern Log Logger;,结果是:

代码语言:javascript
复制
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

代码语言:javascript
复制
#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,我做了:

代码语言:javascript
复制
#include <Utility.h>
...
Utils::Logging::Log Logger;

如果出现以下错误,这将失败:

代码语言:javascript
复制
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

EN

回答 2

Stack Overflow用户

发布于 2020-09-30 09:16:36

记录器需要在.cpp文件中的某个地方实例化。

代码语言:javascript
复制
Log Logger;

仅仅宣布这是不够的。

代码语言:javascript
复制
#include "logger.h"

Utils::Logging::Log Logger;

void Test() {
  Logger << 42;
}
票数 2
EN

Stack Overflow用户

发布于 2020-09-30 09:25:13

可以多次声明全局对象,但必须在整个程序中精确地定义一次。问题是头部可以由多个编译单元(也称为源文件)包含,这意味着头文件中的定义可能导致多个定义。

有几个选择。我会给你两个。

选项1-如果对象位于文件范围内(在任何函数之外,而不是类成员),则可以这样做。

代码语言:javascript
复制
 extern Log Logger;

在头文件中,并将该头包含在多个编译单元中。(如果头包含定义(例如,类定义),则通常需要包含保护以防止单个编译单元多次包含标头)。

然后,在整个项目中的单个编译单元中,包含该标头以获取声明,然后定义它。

代码语言:javascript
复制
 #include "header.h"     // for the definition of Log and the declaration extern Log Logger
 
 Log Logger;               // definition of Logger

选项2-如果对象是类的静态成员,则在类定义中(在标头内)执行

代码语言:javascript
复制
 static Log Logger;

然后在一个单独的编译单元中

代码语言:javascript
复制
 #include "header.h"     // for the definition of the class or struct

 Log WhateverClass::Logger;
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64134370

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档