Windows에서 Visual Studio를 사용하여 C++에서 다양한 템플릿을 지원하는 간단한 로깅 클래스를 작성했습니다. 가능한 입력의 일반적인 조합을 맞추기 위해 많은 수의 특수화 된 일반 Log
함수 템플릿을 만들었습니다.const_cast는 C++ 템플릿에서 무시되는 것 같습니다.
#pragma once
#include <Windows.h>
#include <locale>
#include <codecvt>
#include <string>
#include <sstream>
#include <utility>
using namespace std;
inline static string to_utf8(const wstring& s) {
wstring_convert<codecvt_utf8_utf16<wchar_t>> utf16conv;
return utf16conv.to_bytes(s);
}
class Logger {
public:
HANDLE file_handle;
wchar_t file_path[MAX_PATH + 1];
inline Logger(HANDLE handle) : file_handle(handle), file_path{} {
}
inline Logger(const string& path) : Logger(path.c_str()) {
}
inline Logger(const wstring& path) : Logger(path.c_str()) {
}
inline Logger(const char* path) : file_handle(NULL) {
wstring_convert<codecvt_utf8_utf16<wchar_t>> converter;
wcscpy_s(file_path, MAX_PATH + 1, converter.from_bytes(path).c_str());
}
inline Logger(const wchar_t* path) : file_handle(NULL) {
wcscpy_s(file_path, MAX_PATH + 1, path);
}
private:
inline void VerifyInitialize() {
if ((file_handle == NULL || file_handle == INVALID_HANDLE_VALUE) && file_path[0] != '\0') {
file_handle = CreateFileW(file_path, FILE_GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
SetFilePointer(file_path, 0, NULL, FILE_END);
}
}
public:
inline void Log() {
}
template<typename ...Rest>
inline void Log(const char* first, Rest... params) {
VerifyInitialize();
if (file_handle == NULL || file_handle == INVALID_HANDLE_VALUE)
return;
DWORD written;
WriteFile(file_handle, first, static_cast<DWORD>(strlen(first)), &written, NULL);
Log(params...);
}
template<typename ...Rest>
inline void Log(const char first, Rest... params) {
char str[2];
str[0] = first;
str[1] = '\0';
Log(str, params...);
}
template<typename ...Rest>
inline void Log(const string* first, Rest... params) {
VerifyInitialize();
if (file_handle == NULL || file_handle == INVALID_HANDLE_VALUE)
return;
DWORD written;
WriteFile(file_handle, first->c_str(), static_cast<DWORD>(first->size()), &written, NULL);
Log(params...);
}
template<typename ...Rest>
inline void Log(const string& first, Rest... params) {
Log(&first, params...);
}
template<typename ...Rest>
inline void Log(const wstring* first, Rest... params) {
Log(*first, params...);
}
template<typename ...Rest>
inline void Log(const wstring& first, Rest... params) {
Log(to_utf8(first), params...);
}
template<typename ...Rest>
inline void Log(const wchar_t* first, Rest... params) {
Log(wstring(first), params...);
}
template<typename ...Rest>
inline void Log(const wchar_t first, Rest... params) {
wchar_t str[2];
str[0] = first;
str[1] = '\0';
Log(str, params...);
}
template<typename First, typename ...Rest>
inline void Log(First first, Rest... params) {
printf("%s\n", typeid(First).name());
if (is_const<First>::value) {
stringstream stream;
stream << first;
Log(stream.str(), params...);
} else
Log(const_cast<const First>(first), params...);
}
inline ~Logger() {
if (!(file_handle == NULL || file_handle == INVALID_HANDLE_VALUE)) {
CloseHandle(file_handle);
file_handle = NULL;
}
}
};
코드가 const 값과 잘 작동합니다. 내가 그렇게 같은 const가 아닌 매개 변수를 도입 그러나 경우
int main() {
Logger logger(("output.txt"));
wchar_t sometext[3];
sometext[0] = '1';
sometext[1] = '8';
sometext[2] = '\0';
logger.Log(sometext, L"\n");
return 0;
}
특수화가 호출되지 않고 대신 마지막 일반적인 void Log(First first, Rest... params)
는 stringstream
을 사용하고 대신 문자열 문자열 자체로 포인터를 기록하는 호출됩니다.
나는 모든 과부하 매개 변수, 내가 main()
를 호출 할 때 작동하지만 나는 const char*
와 sometext
를 교체 할 경우, 다음 마지막으로 일반 void Log(First first, Rest... params)
은 (대신 전문의 호출 예. 문제가 해결되지 const
을 제거하는 const
을 제거하는 경우). 이론적 근거는 const를 전문화 과부하 "첫 번째 검색하도록 컴파일러에 지시 인 상태
template<typename First, typename ...Rest>
inline void Log(First first, Rest... params) {
if (is_const<First>::value) {
stringstream stream;
stream << first;
Log(stream.str(), params...);
} else
Log(const_cast<const First>(first), params...);
}
:
그래서 두 세계의 얻는 최선을 다하기 위해, 나는 다음과 같은 조건을 추가 시도 발견되지 않으면 stringstream
"을 사용하여 대체합니다.
그러나 스택 오버 플로우가 발생했습니다. 디버깅하려면, 난 그냥 if
조건 전에 printf("%s\n", typeid(First).name());
을 추가, 출력했다 : 실제로 false
을 반환하는 경우에도 is_const::value
불구하고
wchar_t * __ptr64
wchar_t * __ptr64
wchar_t * __ptr64
wchar_t * __ptr64
....
분명히, const_cast<const First>(first)
이 const
에 캐스팅 사실에 될 것 같지 않습니다. 또한 std::as_const
을 사용해 보았지만 그 결과에는 차이가 없었습니다.
왜 캐스트가 작동하지 않습니까? 이 문제를 어떻게 해결할 수 있습니까?
"const to pointer"전문 분야 외에, 모든 유형에 대해 "const에 대한 포인터"전문 분야를 추가했습니다. 백만 감사 :)) –