Я новичок в C ++ и хотел добавить причудливый способ входа в систему. Таким образом, я создал небольшой фрагмент кода для этого, но мне интересно, как я могу улучшить свой код, особенно тот факт, что DebugColors
состоит из двух файлов, и что касается использования мной шаблонов, я не думаю, что adder
методы структуры Debug — лучший способ объединения строк.
Кроме того, я не уверен, следует ли мне использовать структуру, чтобы содержать методы, или я должен использовать для нее пространство имен, поскольку я хочу иметь доступ только к общедоступным методам извне структуры.
DebugColors.hpp
#ifndef DEBUG_COLORS
#define DEBUG_COLORS
#include <string>
namespace DebugColors {
extern std::string reset;
extern std::string red;
extern std::string green;
extern std::string yellow;
extern std::string blue;
}
#endif
DebugColors.cpp
#include "DebugColors.hpp"
namespace DebugColors {
std::string reset = "x1b[0m";
std::string red = "x1b[31m";
std::string green = "x1b[32m";
std::string yellow = "x1b[33m";
std::string blue = "x1b[34m";
}
Debug.hpp
#ifndef DEBUG_HPP
#define DEBUG_HPP
#include <string>
#include <iostream>
#include "DebugColors.hpp"
struct Debug {
private:
template<typename T>
static T adder(T v) {
return v;
}
template<typename T, typename ...Args>
static T adder(T first, Args ...args) {
return first + " " + adder<std::string>(args...);
}
template<typename ...T>
static void LogMessage(T&... args) {
std::string message = adder<std::string>(args...);
std::cout << message << std::endl;
}
public:
template<typename ...T>
static void Log(T&... args) {
LogMessage(args...);
}
template<typename ...T>
static void Info(T&... args) {
LogMessage(DebugColors::blue, "[INFO]", args..., DebugColors::reset);
}
template<typename ...T>
static void Warning(T&... args) {
LogMessage(DebugColors::yellow, "[WARN]", args..., DebugColors::reset);
}
template<typename ...T>
static void Error(T&... args) {
LogMessage(DebugColors::red, "[ERROR]", args..., DebugColors::reset);
}
template<typename ...T>
static void Success(T&... args) {
LogMessage(DebugColors::green, "[SUCCESS]", args..., DebugColors::reset);
}
};
#endif
```
1 ответ
С использованием namespaces
Мы можем поместить все в namespace
что позволило бы нам использовать using
.
Рассмотрим этот пример,
using Debug::Log; //Error if it's a static member function
// Error msg: error: ‘Debug’ is not a namespace or unscoped enum
namespace Debug{
Type Func(){ ... };
}
using Debug::Func; // No error
Func(); // Calls `Debug::Func`
С, Log
, Info
, Error
, Warning
а также Success
являются просто автономными служебными функциями. Не вижу смысла ставить их в класс.
Мы можем поместить частные функции в другой namespace
сказать impl
, пространство имен, которое будет содержать частные функции Debug
класс.
namespace impl{
std::string add(...) {...}
void LogMessage(...) {...}
}
namespace Debug{
void Log(...) { impl::LogMessage(...) }
void Info(...) { impl::LogMessage(...) }
void Error(...) { impl::LogMessage(...) }
}
Использовать std::to_string
печатать int
песок float
s
Создать to_str
функция, которая будет вызывать std::string
. Почему это необходимо, объясняется в нижеследующих параграфах.
namespace impl {
template<typename T>
std::string to_str(const T& val){
return std::to_string(val);
}
std::string to_str(const std::string& val){
return val;
}
std::string to_str(const char * str){
return std::string(str);
}
} // namespace impl
Свернуть выражение, начиная с C ++ 17
Мы можем использовать выражение свертки при работе с вариативными функциями. Мы можем переписать adder
как таковой.
namespace impl{
template <typename... Args>
std::string adder(Args... args) {
return ((to_str(args) + " ") + ...);
}
}
ссылка на пересылку
Вашу текущую реализацию мы можем использовать только lvalues с функциями. Используя ссылку пересылки, мы можем передать оба lvalues а также rvalues.
namespace Debug{
template <typename... T>
void Log(T&&... args) {
impl::LogMessage(args...);
}
// Similarly for other functions too.
}
Полный код
Debug.hpp
#ifndef DEBUG_HPP
#define DEBUG_HPP
#include <iostream>
#include <string>
#include "DebugColors.h"
namespace impl {
template<typename T>
std::string to_str(const T& val){
return std::to_string(val);
}
std::string to_str(const std::string& val){
return val;
}
std::string to_str(const char * str){
return std::string(str);
}
template <typename... Args>
std::string adder(Args&&... args) {
return ((to_str(args) + " ") + ...);
}
template <typename... T>
void LogMessage(T&&... args) {
std::string message = adder(args...);
std::cout << message << std::endl;
}
} // namespace impl
namespace Debug {
template <typename... T>
void Log(T&&... args) {
impl::LogMessage(args...);
}
template <typename... T>
void Info(T&&... args) {
impl::LogMessage(DebugColors::blue, "[INFO]", args..., DebugColors::reset);
}
template <typename... T>
void Warning(T&&... args) {
impl::LogMessage(DebugColors::yellow, "[WARN]", args..., DebugColors::reset);
}
template <typename... T>
void Error(T&&... args) {
impl::LogMessage(DebugColors::red, "[ERROR]", args..., DebugColors::reset);
}
template <typename... T>
void Success(T&&... args) {
impl::LogMessage(DebugColors::green, "[SUCCESS]", args...,
DebugColors::reset);
}
} // namespace Debug
#endif
test.cpp
include "Debug.hpp"
using Debug::Error;
int main(){
int t = 10;
Error("Danger", 20, t, 3.14);
}
Выход:
Вы можете использовать clang-format
для форматирования файлов кода.
Команда терминала:
clang-format -style=Google -i files
Хороший обзор! Что вы думаете об упоминании
std::string_view
для цветовых кодов?— Эдвард
@ Эдвард, я бы тоже это посоветовал. Но этот переписанный код без необходимости преобразует его в
string
каждый раз. Он также преобразуетconst char*
.— JDłuosz
@ Ch3steR вместо
to_str
назови этоwrap
или что-то, что не подразумевает определенный тип возвращаемого значения. Использоватьstring_view
в качестве прибыли дляconst char*
а такжеstring_view
сам, а такжеstring
поэтому вам не нужно его копировать. Но держиstring
return для чисел и тому подобного, где он выделяет память как часть преобразования.— JDłuosz
@ Эдвард Спасибо. да
string_view
гораздо лучше.— Ч3СТЕР
@ JDługosz Да, согласен,
to_str
без надобности создает копии. Я не рядом со своим ноутбуком. Можете ли вы добавить ответ, поскольку это очень хорошее предложение?— Ч3СТЕР