Depending on how I construct my Log object, I get a compiler error stating that I'm trying to reference a deleted function (the copy constructor):
C:\Projects\Logger\src\Logger.cpp(34,1): error C2280: 'Logger::Log::Log(const Logger::Log &)': attempting to reference a deleted function [C:\Projects\Logger\build\Logger.vcxproj]
It's expected that my Log object has implicitly deleted the copy constructor because:
T has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors);
This makes sense due to std::ofstream which has its copy constructor deleted.
What I can't figure out is why the copy constructor is being called at all. What is it about constructing with the assignment operator that calls the copy constructor? I'm compiling with MSVC, is there some compiler flag I'm not using that doesn't optimize certain behavior? E.g. Construct temporary object then copy construct into named object foo?
There is only one constructor definition as seen in the code block below.
#include <iostream>
#include <string>
#include <fstream>
#include "Logger.h"
#include "LoggerConfig.h"
Logger::Log::Log(std::string file) : filename{ file }
{
logFile = std::ofstream(filename, std::ios::out);
if (logFile.is_open())
{
logFile << "This is a log.\n";
}
else
{
std::cout << "Unable to open filename: " << filename << '\n';
}
}
Logger::Log::~Log()
{
// Wait and take write mutex
// Close file
}
int main()
{
// report version
std::cout << " Version " << LOGGER_VERSION_MAJOR << "."
<< LOGGER_VERSION_MINOR << std::endl;
Logger::Log foo = Logger::Log::Log("sample.log"); // C2280: attemping to reference a deleted function
//Logger::Log foo("sample.log"); // Works!
//Logger::Log foo{"sample.log"}; // Works!
foo.Write(Logger::Log::Level::INFO, "Testing", 123, "hahaha");
return 0;
}
Class interface logger.h below:
#pragma once
namespace Logger
{
class Log
{
private:
std::string filename;
std::ofstream logFile;
public:
enum class Level
{
DEBUG,
INFO,
WARNING,
ERROR
};
Log(std::string file);
~Log();
template<typename T>
void Write(Level lvl, T arg)
{
logFile << arg;
return;
}
template<typename T, typename... Args>
void Write(Level lvl, T firstArg, Args... args)
{
logFile << firstArg;
Write(lvl, args...);
return;
}
};
}