C++新手向cout封裝

意圖通過封裝代碼以在輸出時提供更多信息。

代碼:

//More information when outputting in Debug mode
//<iomanip> setw setfill dec 
//<typeinfo> typeid 
//<sstream> stringstream
//<thread> this_thread 
//<chrono> chrono 
//<ctime> 
#ifdef _DEBUG
#define TYPE(type, var) Type(#var, var, __LINE__, __FUNCTION__, #type)
template <typename T>
void Type(const char* varName, T  var, int line, const char* functionName, const char* type) {
	std::stringstream ss;
	ss << type << " <==> [" << typeid(var).name() << "] ";
	std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
		/*auto now = std::chrono::system_clock::now();*//*TIME*/\
		/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
		/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
		std::cout.width(0);
	std::cout << std::setfill(' ') << std::left << "TYPE "\
		<< std::setw(50) << ss.str()/*TYPE*/\
		<< " At " << std::setw(15) << functionName /*FUNCTION*/\
		<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
		/*<< "File: " << __FILE__ */   /*FILE*/\
		/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
		<< std::endl; \
		std::cout.flags(originalFlags);
}
#define LOG(var) Log(#var, var, __LINE__, __FUNCTION__)
template <typename T>
void Log(const char* varName, T  var, int line, const char* functionName) {
	std::stringstream ss;
	ss << "[" << typeid(var).name() << "] " << varName << " = [" << var << "]";
	std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\

		/*auto now = std::chrono::system_clock::now();*//*TIME*/\
		/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
		/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
		std::cout.width(0);
	std::cout << std::setfill(' ') << std::left << "LOG  "\
		<< std::setw(50) << ss.str()/*TYPE*//*VARIABLE*//*VALUE*/\
		<< " At " << std::setw(15) << functionName /*FUNCTION*/\
		<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
		/*<< "File: " << __FILE__ */   /*FILE*/\
		/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
		<< std::endl; \
		std::cout.flags(originalFlags);
}

#else
template <typename T>
void Type(const char* varName, T  var, int line, const char* functionName) {}
template <typename T>
void Log(const char* varName, T  var, int line, const char* functionName) {}
#endif

使用方式:

LOG(變量);

TYPE(變量的類型, 變量);

這個變量的類型,需要手動填入,填什麼輸出什麼。

範例輸入1:

    LOG(20);
    LOG(3.14158);
    LOG('A');
    LOG("Hello world");
    LOG(false);
    LOG(100000000000000000);

範例輸出1:

LOG  [int] 20 = 20                                     At funcPart0      ,line 00069
LOG  [double] 3.14158 = 3.14158                        At funcPart0      ,line 00070
LOG  [char] 'A' = A                                    At funcPart0      ,line 00071
LOG  [char const * __ptr64] "Hello world" = Hello worldAt funcPart0      ,line 00072
LOG  [bool] false = 0                                  At funcPart0      ,line 00073
LOG  [__int64] 100000000000000000 = 100000000000000000 At funcPart0      ,line 00074

範例輸入2:

    int a = 30;
    LOG(a);
    long long ffffffffffffffffffffffffffffff = 1;
    LOG(ffffffffffffffffffffffffffffff);
    char c = 'a';
    char* ptrC = &c;
    LOG(ptrC);
    LOG(&ptrC);
    LOG(*&*&*&*(ptrC));

範例輸出2:

LOG  [int] a = 30                                       At funcPart0      ,line 00065
LOG  [__int64] ffffffffffffffffffffffffffffff = 1       At funcPart0      ,line 00067
LOG  [char * __ptr64] ptrC = a昍昍昍昍昍昍昍昍昍昍昍昍昍昍昍昍昍怳? At funcPart0      ,line 00070
LOG  [char * __ptr64 * __ptr64] &ptrC = 000000E89092F4C8 At funcPart0      ,line 00071
LOG  [char] *&*&*&*(ptrC) = a                           At funcPart0      ,line 00072

(輸出第三行這個指針的內容有亂碼,只有第一字被寫入內容,畢竟是個char麻)

範例輸入3:

    LOG(std::dec);

    int a = 40;
    TYPE(int, a);

    std::ios_base::fmtflags ff;
    ff = std::cout.flags();
    TYPE(std::ios_base::fmtflags, ff);

範例輸出3:

LOG  [class std::ios_base & __ptr64 (__cdecl*)(class std::ios_base & __ptr64)] std::dec =  At funcPart0      ,line 00064
TYPE int <==> [int]                                     At funcPart0      ,line 00067
TYPE std::ios_base::fmtflags <==> [int]                 At funcPart0      ,line 00071

以下是關於輸出3的解釋:

在xiosbase文件中第93行,可以看到fmtflag確實是int。

    using fmtflags = int;

在ios文件第190行,可以看到std::dec函數,這是跟輸出流和調用慣例相關的底層函數實現,不必在意。

_EXPORT_STD inline ios_base& __CLRCALL_OR_CDECL dec(ios_base& _Iosbase) { // set basefield to dec
    _Iosbase.setf(ios_base::dec, ios_base::basefield);
    return _Iosbase;
}

在vcruntime文件第140行,macro __CLRCALL_OR_CDCEL被替換成了 __cdcel。

// Definitions of calling conventions used code sometimes compiled as managed
#if defined _M_CEE_PURE || defined MRTDLL
    (條件編譯失敗)#define __CLRCALL_OR_CDECL __clrcall
    (條件編譯失敗)#define __CLR_OR_THIS_CALL __clrcall
#else
    #define __CLRCALL_OR_CDECL __cdecl
    #define __CLR_OR_THIS_CALL
#endif

然後int就是int,這個應該沒問題。

代碼說明:

1.用macro替換成Type(#var, var, __LINE__, __FUNCTION__, #type)。

其中#var是第二個參數文字。二是第二個參數。三是行數。四是文件名。五是第一個參數的名。

2.調用Type或Log函數。

3.進入模板函數開始輸出。

結語:

我在玩和深挖代碼時,需要一個好的環境, 如果有一個模板可以複製貼上,那可以減低重複性的工作並提高效率,在此提供我的參考。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <sstream>
#include <chrono>
//#include <thread>
//#include <ctime>



//More information when outputting in Debug mode
//<iomanip> setw setfill dec 
//<typeinfo> typeid 
//<sstream> stringstream
//<thread> this_thread 
//<chrono> chrono 
//<ctime> 
#ifdef _DEBUG
#define TYPE(type, var) Type(#var, var, __LINE__, __FUNCTION__, #type)
template <typename T>
void Type(const char* varName, T  var, int line, const char* functionName, const char* type) {
	std::stringstream ss;
	ss << type << " <==> [" << typeid(var).name() << "] ";
	std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
		/*auto now = std::chrono::system_clock::now();*//*TIME*/\
		/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
		/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
		std::cout.width(0);
	std::cout << std::setfill(' ') << std::left << "TYPE "\
		<< std::setw(50) << ss.str()/*TYPE*/\
		<< " At " << std::setw(15) << functionName /*FUNCTION*/\
		<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
		/*<< "File: " << __FILE__ */   /*FILE*/\
		/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
		<< std::endl; \
		std::cout.flags(originalFlags);
}
#define LOG(var) Log(#var, var, __LINE__, __FUNCTION__)
template <typename T>
void Log(const char* varName, T  var, int line, const char* functionName) {
	std::stringstream ss;
	ss << "[" << typeid(var).name() << "] " << varName << " = [" << var << "]";
	std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\

		/*auto now = std::chrono::system_clock::now();*//*TIME*/\
		/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
		/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
		std::cout.width(0);
	std::cout << std::setfill(' ') << std::left << "LOG  "\
		<< std::setw(50) << ss.str()/*TYPE*//*VARIABLE*//*VALUE*/\
		<< " At " << std::setw(15) << functionName /*FUNCTION*/\
		<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
		/*<< "File: " << __FILE__ */   /*FILE*/\
		/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
		<< std::endl; \
		std::cout.flags(originalFlags);
}

#else
template <typename T>
void Type(const char* varName, T  var, int line, const char* functionName) {}
template <typename T>
void Log(const char* varName, T  var, int line, const char* functionName) {}
#endif


//
void funcPart0()
{

}

//
void funcPart1()
{

}

//
void funcPart2()
{

}

//
void funcPart3()
{

}

//
void funcPart4()
{

}

//
void funcPart5()
{

}

//
void funcPart6()
{

}

//
void funcPart7()
{

}

//
void funcPart8()
{

}

//
void funcPart9()
{
}

void doAllFuncPart(void (**f)())
{
	for (int i = 0; i < 10; ++i)
	{
		f[i]();
	}

}

int main() {
	auto start_time = std::chrono::high_resolution_clock::now();
	void (*funcPart[10])() = { funcPart0 ,funcPart1 ,funcPart2 ,funcPart3 ,funcPart4 ,funcPart5 ,funcPart6 ,funcPart7 ,funcPart8,funcPart9 };
	doAllFuncPart(funcPart);


	auto end_time = std::chrono::high_resolution_clock::now();
	auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
	std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;

	return 0;
}

註:我會回來更新函數,如果我找到更好的或是更新了函數,只會改最下面的代碼,所以範例可能會稍有不同。

2024/04/28 新的參考

新年新氣象,這都用上spdlog、catch2和分文件了了。

文件

funcPart_00_09.cpp文件

#include "funcPart_00_09.h"

void funcPart00()
{
}

void funcPart01()
{
}

void funcPart02()
{
}

void funcPart03()
{
}

void funcPart04()
{
}

void funcPart05()
{
}

void funcPart06()
{
}

void funcPart07()
{
}

void funcPart08()
{
}

void funcPart09()
{
}

funcPart_00_09.h文件

#ifndef FUNCPART_00_09_H
#define FUNCPART_00_09_H

#include "common.h"

void funcPart00();

void funcPart01();

void funcPart02();

void funcPart03();

void funcPart04();

void funcPart05();

void funcPart06();

void funcPart07();

void funcPart08();

void funcPart09();

#endif 

此外還有

funcPart_10_19.h 到 funcPart_90_99.h

funcPart_10_19.cpp 到 funcPart_90_99.cpp。

main.cpp文件

#include "catch2/catch_amalgamated.hpp"
#include "common.h"
#include "funcPart_00_09.h"
#include "funcPart_10_19.h"
#include "funcPart_20_29.h"
#include "funcPart_30_39.h"
#include "funcPart_40_49.h"
#include "funcPart_50_59.h"
#include "funcPart_60_69.h"
#include "funcPart_70_79.h"
#include "funcPart_80_89.h"
#include "funcPart_90_99.h"


void doAllFuncPart(void (**f)(), int count)
{
	for (int i = 0; i < count; ++i)
	{
		f[i]();
	}
}



int main(int argc, char* argv[]) {

	/*函數時間測量代碼*/
	auto start_time = std::chrono::high_resolution_clock::now();

	/*執行所有函數代碼*/
	void (*funcPart[])() = {
		funcPart00, funcPart01, funcPart02, funcPart03, funcPart04, funcPart05, funcPart06, funcPart07, funcPart08, funcPart09, 
		funcPart10, funcPart11, funcPart12, funcPart13, funcPart14, funcPart15, funcPart16, funcPart17, funcPart18, funcPart19,
		funcPart20, funcPart21, funcPart22, funcPart23, funcPart24, funcPart25, funcPart26, funcPart27, funcPart28, funcPart29,
		funcPart30, funcPart31, funcPart32, funcPart33, funcPart34, funcPart35, funcPart36, funcPart37, funcPart38, funcPart39,
		funcPart40, funcPart41, funcPart42, funcPart43, funcPart44, funcPart45, funcPart46, funcPart47, funcPart48, funcPart49,
		funcPart50, funcPart51, funcPart52, funcPart53, funcPart54, funcPart55, funcPart56, funcPart57, funcPart58, funcPart59,
		funcPart60, funcPart61, funcPart62, funcPart63, funcPart64, funcPart65, funcPart66, funcPart67, funcPart68, funcPart69,
		funcPart70, funcPart71, funcPart72, funcPart73, funcPart74, funcPart75, funcPart76, funcPart77, funcPart78, funcPart79,
		funcPart80, funcPart81, funcPart82, funcPart83, funcPart84, funcPart85, funcPart86, funcPart87, funcPart88, funcPart89,
		funcPart90, funcPart91, funcPart92, funcPart93, funcPart94, funcPart95, funcPart96, funcPart97, funcPart98, funcPart99,
	};
	int funcCount = sizeof(funcPart) / sizeof(funcPart[0]);
	doAllFuncPart(funcPart, funcCount);

	/*catch2代碼*/
	// 初始化 Catch2 的 Session
	Catch::Session session;
	// 處理命令行參數
	int result = session.applyCommandLine(argc, argv);
	if (result != 0) { // 命令行參數錯誤
		return result;
	}
	// 運行所有測試
	int numFailed = session.run();


	/*函數時間測量代碼*/
	auto end_time = std::chrono::high_resolution_clock::now();
	auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
	std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " milliseconds" << std::endl;

	/*catch2代碼*/
	//返回失敗的測試數量
	return numFailed;
}

catch_main.cpp文件,catch2去github抓。

#define CATCH_CONFIG_MAIN  // 這行告訴 Catch 提供 main() 函數
#include "catch2/catch_amalgamated.hpp"
#include "catch2/catch_amalgamated.cpp"

common.h 通用工具文件

#ifndef COMMON_H
#define COMMON_H

#define _CRT_SECURE_NO_WARNINGS
#include <spdlog/spdlog.h>
#include <catch2/catch_amalgamated.hpp>

#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <sstream>
#include <chrono>
#include <stdexcept>

//#include <thread>
//#include <ctime>



//More information when outputting in Debug mode
//<iomanip> setw setfill dec 
//<typeinfo> typeid 
//<sstream> stringstream
//<thread> this_thread 
//<chrono> chrono 
//<ctime> 
#ifdef _DEBUG
#define TYPE(type, var) Type(#var, var, __LINE__, __FUNCTION__, #type)
template <typename T>
void Type(const char* varName, T  var, int line, const char* functionName, const char* type) {
	std::stringstream ss;
	ss << type << " <==> [" << typeid(var).name() << "] ";
	std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
		/*auto now = std::chrono::system_clock::now();*//*TIME*/\
		/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
		/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
		std::cout.width(0);
	std::cout << std::setfill(' ') << std::left << "TYPE "\
		<< std::setw(50) << ss.str()/*TYPE*/\
		<< " At " << std::setw(15) << functionName /*FUNCTION*/\
		<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
		/*<< "File: " << __FILE__ */   /*FILE*/\
		/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
		<< std::endl; \
		std::cout.flags(originalFlags);
}
#define LOG(var) Log(#var, var, __LINE__, __FUNCTION__)
template <typename T>
void Log(const char* varName, T  var, int line, const char* functionName) {
	std::stringstream ss;
	ss << "[" << typeid(var).name() << "] " << varName << " = [" << var << "]";
	std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\

		/*auto now = std::chrono::system_clock::now();*//*TIME*/\
		/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
		/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
		std::cout.width(0);
	std::cout << std::setfill(' ') << std::left << "LOG  "\
		<< std::setw(50) << ss.str()/*TYPE*//*VARIABLE*//*VALUE*/\
		<< " At " << std::setw(15) << functionName /*FUNCTION*/\
		<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
		/*<< "File: " << __FILE__ */   /*FILE*/\
		/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
		<< std::endl; \
		std::cout.flags(originalFlags);
}

#else
template <typename T>
void Type(const char* varName, T  var, int line, const char* functionName) {}
template <typename T>
void Log(const char* varName, T  var, int line, const char* functionName) {}
#endif

#endif // COMMON_H

把spdlog/include和catch2.h catch2.cpp放在third_party目錄下, 記得在visual studio 2022的VC++ 裡面的包含目錄加上$(SolutionDir)/third_party;,這樣能通過<>去包含,就這樣吧,之後幾天應該會把operator overloading的教學發上來。

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值