이것은 매크로에서 가능한 사용 일방시스입니까? 템플릿으로 변환 할 수 있습니까?
-
03-07-2019 - |
문제
괜찮은 로깅을 위해 Clogclass를 구현 한 후에는 매크로를 정의했지만 하나의 매개 변수와 함께 작동합니다 ...
class CLogClass
{
public:
static void DoLog(LPCTSTR sMessage, ...);
};
#define DebugLog(sMessage, x) ClogClass::DoLog(__FILE__, __LINE__, sMessage, x)
글쎄, 그것은 2 개 이상의 매개 변수로 호출되면 실패합니다.
편집 : Variadic 매크로는 2005 년 대에 도입되었습니다 (그러나 현재 vs 2003에 있습니다 ...). 조언이 있습니까?
해결책
MyLog 매크로가 변수 수의 인수를 취하는 사용자 정의 functor 객체를 반환 할 수 있습니다.
#include <string>
#include <cstdarg>
struct CLogObject {
void operator()( const char* pFormat, ... ) const {
printf( "[%s:%d] ", filename.c_str(), linenumber );
va_list args;
va_start( args, pFormat );
vfprintf( stderr, pFormat, args );
va_end( args );
}
CLogObject( std::string filename, const int linenumber )
: filename( filename ), linenumber( linenumber )
{}
std::string filename;
int linenumber;
};
#define MYLOG CLogObject( __FILE__, __LINE__ )
int _tmain(int argc, _TCHAR* argv[])
{
MYLOG( "%s, %d", "string", 5 );
return 0;
}
만지는 타입 안전 변형으로 넘어가는 것은 그리 어렵지 않습니다. 이 답변: 연쇄 효과로 인해 변동성 주장이 필요하지 않습니다. operator<<
.
struct CTSLogObject {
template< typename T >
std::ostream& operator<<( const T& t ) const {
return std::cout << "[" << filename << ":" << linenumber << "] ";
}
CTSLogObject( std::string filename, const int linenumber )
: filename( filename ), linenumber( linenumber )
{}
std::string filename;
int linenumber;
};
#define typesafelog CTSLogObject( __FILE__, __LINE__ )
int _tmain(int argc, _TCHAR* argv[])
{
typesafelog << "typesafe" << ", " << 5 << std::endl;
return 0;
}
다른 팁
귀하의 질문은 실제로 두 가지 답변에 호소합니다. Printf와 같이 작동하지만 완전히 사용자 정의 할 수있는 범용 로깅 기능을 수행하려고합니다. 그래서 당신은 필요합니다 :
- 가변 수의 인수를 취하는 매크로
- 변수 수의 인수를 취하는 함수
다음은 ADATAPTED CODE 예제입니다.
#include <stdio.h>
#include <stdarg.h>
class CLogClass
{
public:
static void DoLogWithFileLineInfo( const char * fmt, ... )
{
va_list ap;
va_start( ap, fmt );
vfprintf( stderr, fmt, ap );
va_end( ap );
}
};
#define MYLOG(format, ...) CLogClass::DoLogWithFileLineInfo("%s:%d " format , __FILE__, __LINE__, __VA_ARGS__)
int main()
{
MYLOG("Hello world!\n", 3); // you need at least format + one argument to your macro
MYLOG("%s\n", "Hello world!");
MYLOG("%s %d\n", "Hello world!", 3);
}
Variadic 매크로는 C99에 도입되었으므로 C99 또는 C ++ 0x를 지원하는 컴파일러에서 작동합니다. GCC 3.4.2 및 Visual Studio 2005로 성공적으로 테스트했습니다.
기능에 대한 변동성 주장은 영원히 존재 했으므로 여기에 계산 가능성에 대해 걱정하지 않았습니다.
일부 템플릿 메타 프로그램으로 수행 할 수는 있지만 위의 코드의 단순성을 감안할 때 관심을 보지 못했습니다.
마지막으로, 왜 기능 대신 빈 클래스에서 정적 메소드를 사용합니까?
class Log {
stringstream buffer;
public:
class Proxy {
public:
Proxy(Log& p) : parent(p) {}
template<class T>
Proxy& operator,(T const& t) {
parent.buffer << t;
return *this;
}
~Proxy() {
parent.buffer << endl;
cout << parent.buffer.str();
parent.buffer.str("");
}
private:
CLog& parent;
};
template<class T>
Proxy operator<<(T const& t) {
buffer << t;
return Proxy(*this);
}
};
타임 스탬프를 작성하고 로그 레벨을 확인하고 파일에 쓰기 등을 위해 사소하게 확장 될 수 있습니다.
또는 더 간단하지만 덜 유연하게 :
class Log {
public:
class Proxy {
public:
template<class T>
Proxy& operator,(T const& t) {
cout << t;
return *this;
}
~Proxy() {
cout << endl;
}
};
template<class T>
Proxy operator<<(T const& t) {
cout << t;
return Proxy();
}
};
용법:
Log log;
void f() {
log << "hey, my age is ", age;
}
이 인스턴스에서 매크로가 아닌 전역으로 보이는 외부 함수를 사용하는 경향이 있으며 VA_LIST를 사용 하여이 함수의 엘립스 시스를 해결하는 경향이 있습니다. 내 이전 게시물을 참조하십시오 이를 달성하는 방법에 대한 예.