Reputation: 11
I am trying to write logger.
This is my header file with logger
#include <iostream>
void logInfo(){}
void logWarning(){}
void logError(){}
void logDebug(){}
template<typename First, typename ...Rest>
void logInfo(First && first, Rest && ...rest)
{
std::cout << "[INFO] " << std::forward<First>(first) << std::endl;
logInfo(std::forward<Rest>(rest)...);
}
template<typename First, typename ...Rest>
void logWarning(First && first, Rest && ...rest)
{
std::cout << "[WARNING] " << std::forward<First>(first) << std::endl;
logWarning(std::forward<Rest>(rest)...);
}
template<typename First, typename ...Rest>
void logError(First && first, Rest && ...rest)
{
std::cout << "[ERROR] " << std::forward<First>(first) << std::endl;
logError(std::forward<Rest>(rest)...);
}
template<typename First, typename ...Rest>
void logDebug(First && first, Rest && ...rest)
{
std::cout << "[DEBUG] " << std::forward<First>(first) << std::endl;
logDebug(std::forward<Rest>(rest)...);
}
Then if I will include this logger to main it is working okay:
#include "CLogger.hpp"
using namespace std;
int main()
{
logInfo("something");
}
But if I'm trying to include logger in other class:
#include <iostream>
#include "CFileManager.hpp"
#include "CLogger.hpp"
const char* CFileManager::PWD_COMMAND = "PWD";
const std::string CFileManager::DATA_FILE_NAME = "/data.txt";
CFileManager::CFileManager()
: mFile()
, mPathToFile( getenv( PWD_COMMAND ) )
{
mFile = std::ofstream{ mPathToFile + DATA_FILE_NAME };
}
CFileManager::~CFileManager()
{
mFile.close();
}
Binary doesn't compile. This is error:
/usr/bin/ld: CFileManager.o: in function `logInfo()':
CFileManager.cpp:(.text+0x0): multiple definition of `logInfo()'; main.o:main.cpp:(.text+0x0): first defined here
/usr/bin/ld: CFileManager.o: in function `logWarning()':
CFileManager.cpp:(.text+0xb): multiple definition of `logWarning()'; main.o:main.cpp:(.text+0xb): first defined here
/usr/bin/ld: CFileManager.o: in function `logError()':
CFileManager.cpp:(.text+0x16): multiple definition of `logError()'; main.o:main.cpp:(.text+0x16): first defined here
/usr/bin/ld: CFileManager.o: in function `logDebug()':
CFileManager.cpp:(.text+0x21): multiple definition of `logDebug()'; main.o:main.cpp:(.text+0x21): first defined here
It could be the case, that I missing something in makefile?:
#folders
IMPL_DIR := src
HEADER_DIR := include
BIN_DIR := bin
#flags
CCFLAGS := -Wall -Wextra -pedantic -std=c++17
IINCLUDE := -I$(HEADER_DIR)
#output
output: main.o CFileManager.o
g++ $(CCFLAGS) $(IINCLUDE) main.o CFileManager.o -o $(BIN_DIR)/login
#main
main.o: main.cpp | $(BIN_DIR)
g++ $(IINCLUDE) -c main.cpp
#fileManager
CFileManager.o: $(HEADER_DIR)/CFileManager.hpp $(IMPL_DIR)/CFileManager.cpp
g++ $(IINCLUDE) -c $(IMPL_DIR)/CFileManager.cpp
#create bin folder
$(BIN_DIR):
mkdir -p $@
#make clean
.PHONY: clean
clean:
$(RM) *.o
Because I doesn't change anything in makefile, because this is only header. What's wrong?
Did you know how could I add more information to the log? I want to see:
Can I somehow modify my code easily? Or should I re implement completely?
Upvotes: 1
Views: 3343
Reputation: 218278
void logInfo(){}
void logWarning(){}
void logError(){}
void logDebug(){}
Are regular functions, so if included in different translation unit, you have multiple definitions.
Marking them inline would solve the issue:
inline void logInfo(){}
inline void logWarning(){}
inline void logError(){}
inline void logDebug(){}
For your specific case, you might rewrite your template method to avoid the need of those methods BTW:
template<typename... Ts>
void logInfo(Ts&&...args)
{
((std::cout << "[INFO] " << std::forward<Ts>(args) << std::endl), ...);
}
Upvotes: 3