Here is the solution I found. The only thing I don't like in it is the use of
coffee_format[]
being a global variable.
#include <chrono>
#include <fstream>
#include <iostream>
#include <format>
template<const char* format, typename... Args>
void WriteLogFile(const std::string& filename, const char* file, int line, Args&&... args)
{
std::ofstream logFile(filename, std::ios_base::app);
if (!logFile)
{
std::cerr << "Failed to open log file." << std::endl;
return;
}
auto now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::string message = std::format(format, std::ctime(¤tTime), file, line, std::forward<Args>(args)...);
logFile << message << std::endl;
std::cout << message << std::endl;
logFile.close();
}
constexpr char coffee_format[] = "{} [{}:{}] - Brewing a cup of {} with {}ml of milk at {} degrees.";
void BrewCoffee(const std::string& coffeeType, int milkAmount, int temperature)
{
WriteLogFile<coffee_format>("coffeeMachine.log", __FILE__, __LINE__, coffeeType, milkAmount, temperature);
}
int main()
{
BrewCoffee("Espresso", 0, 90);
BrewCoffee("Cappuccino", 150, 85);
return 0;
}
Update:
Actually its not a good solution because it misses the idea of a function such as WriteLogFile() which is supposed to have the flexibility to be used, for example, like this:
int main()
{
WriteLogFile("coffeeMachine.log", __FILE__, __LINE__,
"Program started as {}.",
std::chrono::system_clock::now());
BrewCoffee("Espresso", 0, 90);
BrewCoffee("Cappuccino", 150, 85);
return 0;
}
This can be solved by using a Templated Functor and a lambda
#include <chrono>
#include <fstream>
#include <iostream>
#include <format>
template<typename FormatFunctor, typename... Args>
void WriteLogFile(const std::string& filename, const char* file, int line, FormatFunctor formatFunctor, Args&&... args)
{
std::ofstream logFile(filename, std::ios_base::app);
if (!logFile)
{
std::cerr << "Failed to open log file." << std::endl;
return;
}
auto now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::string message = formatFunctor(std::ctime(¤tTime), file, line, std::forward<Args>(args)...);
logFile << message << std::endl;
std::cout << message << std::endl;
logFile.close();
}
void BrewCoffee(const std::string& coffeeType, int milkAmount, int temperature)
{
auto formatFunctor = [](auto... args)
{
return std::format("{} [{}:{}] - Brewing a cup of {} with {}ml of milk at {} degrees.", args...);
};
WriteLogFile("coffeeMachine.log", __FILE__, __LINE__, formatFunctor, coffeeType, milkAmount, temperature);
}
int main()
{
auto startFormatFunctor = [](auto... args)
{
return std::format("{} [{}:{}] - Program has started at {}.", args...);
};
auto now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
WriteLogFile("coffeeMachine.log", __FILE__, __LINE__, startFormatFunctor, std::ctime(¤tTime));
BrewCoffee("Espresso", 0, 90);
BrewCoffee("Cappuccino", 150, 85);
return 0;
}