私は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
を削除し、私はconst char*
でsometext
を置き換える場合は、最後のジェネリックvoid Log(First first, Rest... params)
は、すなわち(代わりに特殊化と呼ばれている。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へのポインタ"特殊化を追加しました。百万こんにちは:)) –