Files
RepoMain/ZCppMain/ZMainHead.H
2021-03-25 16:51:46 +09:00

4762 lines
192 KiB
C++

/*//////////////////////////////////////////////////////////////////////////////////////
■ unsigned 정수형은 가급적이면 쓰지 말자. 일반적으로 많이 쓰는 signed 정수와의 호환이
'약간' 거슬리고 있는데, 이 '약간' 이라도 왠지 찝찝하다. 2008-09-14 03:24:00
■ 해당 namespace 에서 필요한 상수는 그 namespace 안에서 상수전용 namespace ZNsConst 를
만들고 그 안에 둔다.
해당 namespace 에서 필요한 enum 는 그 namespace 안에서 enum 전용 namespace ZNsEnum 를
만들고 그 안에 둔다. 해당 enum 형을 문자열로 돌려주는 함수는, 동일한 네임스페이스 안
const char* GetMSG_enum_data_type(int AI_Enum);
const char* GetMSG_enum_data_type(enum_data_type AE_Enum);
의 형태로 설계한다.
--
필요하면 ZNsEnum, ZNsConst 를 접두어로 하는 namespace 를 만들고 그 안에서 필요한 enum
자료형이나 상수형을 정의할 수 있다.
-- 2010-06-13 22:37:00
■ 해당 namespace 에서 특정 클래스에 필요한 단순히 인터페이스를 알리주는 클래스나 함수는
그 namespace 안에서 interface 전용 namespace ZNsInterface 를 만들고 그 안에 둔다. 멤버
변수가 없이 순수 interface 로만 사용되는 클래스는 'C' 가 아닌 'I' 로 시작한다.
■ 복잡한 템플릿 인수 타입 관계를 정리하기 위해 사용하는 class 에는 ZtCType 이라는 접두어
를 붙이고 모두 namespace ZNsType 에 둔다.
■ 주로 예제 용도로 작성하는 클래스는 namespace ZNsExam 에 둔다. 주로 복잡한 템플릿 인수
를 가지는 클래스에 대한 예제일 것이다.
■ 복잡한 템플릿 인수 타입 관계를 정리하기 위해 Proxy 로 사용하는 class 에는 CProxy 이라
는 접두어를 붙이고 모두 namespace ZNsIProxy 에 둔다.(Interface Proxy) 실제 Proxy 를 구
현하는 클래스는 CProxy 라는 접두어를 붙이고 namespace ZNsProxy 안에 둔다.
ZNsIProxy 와 ZNsProxy 를 다른 용도로 쓰고 있는 것이다.
■ 특정 클래스 안에서만 사용되어 사용자가 그 존재를 알 필요가 없는 클래스는
namespace ZNsHide
에 둔다.
■ 같은 이름의 일반 함수와 템플릿 함수가 있어면 좋은 상황에서 하는데, 함수를 일반 함수와
템플릿 함수로 중첩시키기가 힘들 때, 템플릿 함수를 일반함수가 속한 namespace 안에 또
다른 namespace ZNsTmpl 에 둔다.
cf) std::ZNsTmpl::FindPos();
■ 어떤 클래스(템플릿)이 거의 같은 기능을 하지만, Decoration 패턴을 사용하는 클래스와,
그렇지 않은 클래스가 쌍으로 존재할 때, Decoration 패턴을 사용하는 클래스는 주로
namespace ZNsDeco
에 둔다. Decoration 패턴은 Logic 과 View 구조에서, View 에 해당하는 클래스를, Logic
클래스 의 생성자에서 (주로) 참조로 전달받는 경우를 말한다.
■ 클래스 템플릿 설계할 때 핵심 기능만 구현하고 나머지 부분은 기초클래스나 상속클래스,
혹은 멤버가 되는 클래스로 설계할 수 있는데, 이 클래스들의 이름에 적절한 이름을 붙이기
어려운 경우에는 CHelp~ 로 시작하는 이름으로 하자. 이외에도 Business Logic 과 View 의
분리라는 뜻에서 CView~ 도 생각할 수 있다.
cf) class CHelpIOCP
■ template 으로 어떤 main class 를 디자인할 때 다른 class template 을 인수로 받는 경우
가 있겠고 이때 클래스 템플릿 인수의 instance 의 멤버를 셋팅하려면 그 template 의 모든
멤버에 대하여 public 권한을 갖게 되는 경우가 많을 것이다. 이때는 셋팅 권한을 갖는 멤
버를 외부 기초 클래스 template 으로 만들고(따라서 main class 는 이 기초클래스를 상속
한다.) 이 class 에서 friend 지정을 하면 될 것이다. 그런데 main class 도 템플릿일 것으
므로 기초 클래스가 정의되기 전에는 정의될 수 없다는 문제가 있다. 이 문제를 피하기 위
해 main class 를 상속하는 비템플릿 클래스를 선언하고 (정의는 나중으로 미루고 전방선언
만 한다.) 기초 클래스에서 이 클래스에 friend 지정을 하면 될 것이다.
아니면 public 이 아니어야 할 멤버 함수가 템플릿 설계로 인해 어쩔 수 없이 public 으로
해야 할때 No Public 을 의미하는 macro _NP_ 를 그 함수 선언과 정의 앞에 붙여주자
■ 함수가 어떤 조건에서 실행을 중지할 때, bool 값으로 표시해도 되지만 가독성을 위해서
enum std::ZNsEnum::ERun
을 사용하자.
■ 함수가 굳이 어떤 값을 리턴할 필요는 없는데, 함수의 역할이 특정 조건인지 체크해서 그
조건에 맞으면 어떤 작업을 실행한다고 할 때, 이 실행여부를 굳이 리턴하고자 한다면 bool
형 대신에, 가독성을 위해서 enum std::ZNsEnum::EAct 을 사용하자.
■ call back 함수나 이떤 이벤트마다 실행하는 함수는 접두어 'On' 을 붙이자. 어떤 컨테이너
의 각 원소마다 특정한 처리를 하는 함수에는 'Iter' 를 붙이자.
cf) CDoubleList<int>::IterElement();
'Iter' 대신에 'OnEach' 를 붙여도 좋을 것 같다.
■ 클래스의 초기와, 종료함수를 별도로 지정할 때에는 각각 접두어 Init, Fini 뒤에 적절한
이름을 붙여주자. 클래스의 초기와, 종료함수를 Init, Fini 로만 지정했더니, 나중에는 비
슷비슷한 이름이 많아서 상속할 때 상당히 햇깔렸다.
클래스의 멤버중에 단순히 멤버를 0 과 같은 초기값으로 셋팅하는 함수는 InitVar 라는 함
수명을 사용하자.
■ containter class template 는 TypeData 라는 type 을 가져야 한다. 예를 들어
CObjList<int>::TypeData
라는 접근이 가능해야 한다. 이 표기에서 int 가 TypeData 라는 것은 분명히 알 수 있으나
containter 형을 인수로 받는 템플릿에서, 그 템플릿이 어떤 자료형 (예에서는 int)에 대한
containter 인지 모르게 된다. 이것을 해결하기 위한 (템플릿을 편리하게 하기 위한)규칙이
다.
이외에도 컨테이너의 컨테이너와 같은 복잡한 컨테이너 type 을 템플릿 인수로 여러 개 갖
는 컨테이너에서 TypeData 외에 추가적인 정의를 할 수 있겠다. 이런 type 이 이름은 Type
으로 시작하는 것으로 하자.
cf) IN ZNsCPP::CStringSerial_T<>
typedef TTypeCh TypeData ;
typedef TStringType TypeCStringData ;
typedef TStringList TypeCStringList ;
※ 그런데 꼭 container class template 가 아니라 할지라도 class template 은 내부적으
로 대표 자료형 TypeData 형을 갖도록 하는 것이 좋을 것 같다. 2008-11-05 13:22:00
※ TString 에 외부 접근 형 정의를 한다면 TypeCString 이 아니라 TypeString 으로 하는
것이 좀 예쁜(?) 것 같다.
typedef TString TypeCString;
typedef TString TypeString ;
2 번 줄 코드가 좀 낳아 보이지 않을까. 2008-11-05 13:42:00
■ template 함수나 클래스에서 functor 인수는 참조로 선언하지 않는다. 아래 참고,
InputIterator& first, InputIterator& last
이라고 하지 않았다. 단순 함수나 크기가 작은 object 일 경우 느려질 수 있기 때문이다.
단 아래 for_each 예에서 InputIterator 가 클래스일 경우 복사 생성자를 꼭 가져야 한다.
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)
{
while ( first!=last ) f(*first++);
return f;
}
■ WINDOW 에서 UNICODE 로 컴파일할 경우 아래 3 개의 매크로를 추가할 것.
#define _MBCS
#define _UNICODE
#define UNICODE
■ 구 버전의 컴파일러에서 RTTI 옵션이 꺼져 있으면 헤더파일 typeinfo 을 사용할 수 없다.
■ breakpoint assembly
_asm
{
int 3;
}
■ 리눅스 core file 무제한 명령
ulimit -c unlimited
system("ulimit -c unlimited");
■ Visual C++ 2008 에 추가된 함수를 사용할려면 아래 매크로를 정의한다.
#define _WIN32_WINNT 0x0600
-- 2010-04-22 19:55:00
■ _REENTRANT_EX 매크로를 정의하면 _REENTRANT 보다 좀더 최적화된 thread-safe 함수를
사용하거나, 약간 실험적인 thread-safe 함수를 사용한다.
-- 2011-03-13 01:04:00
//////////////////////////////////////////////////////////////////////////////////////*/
#ifndef __MAINHEADER_H__
#define __MAINHEADER_H__
#include <cstdio>
#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <string>
#include <climits>
#include <typeinfo>
#define _CODE_OLD_ 0
#define _CODE_BAD_ 0
#define _CODE_NEW_ 1
/*/////////////////////////////////////////////////////////////////
■ 위 매크로 _CODE_OLD_ 와 _CODE_NEW_ 등은 #if(0) 이나 #if(1) 등으
로 폐기되거나 추가된 코드를 나타냈던 것을 좀 더 직관적으로 표현
한다.
-- 2013-07-28 16:21:00
/////////////////////////////////////////////////////////////////*/
#define _COMMENT_ 0 // 주석으로 사용하는 부분.
#if defined(_WIN32) || defined(_WIN64) || defined(_WIN128) || \
defined( WIN32) || defined( WIN64) || defined( WIN128)
#ifndef _WIN
#define _WIN
#endif
#endif/*
defined(_WIN32) || defined(_WIN64) || defined(_WIN128) || \
defined( WIN32) || defined( WIN64) || defined( WIN128) */
#if defined(_WIN64) || defined( WIN64)
#ifndef __CPU_BIT_CNT__
#define __CPU_BIT_CNT__ 64
#endif
#endif /*defined(_WIN64) || defined( WIN64) */
#if defined(_WIN128) || defined( WIN128)
#ifndef __CPU_BIT_CNT__
#define __CPU_BIT_CNT__ 128
#endif
#endif /*defined(_WIN128) || defined(WIN128) */
#if defined(_WIN)
typedef signed char int8_t ;
typedef unsigned char uint8_t ;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#ifndef __VISUAL_CPP_VER__
#define __VISUAL_CPP_VER__ 200800 // 끝 2 자리는 소수점 버전
#endif//__VISUAL_CPP_VER__
#elif defined(__mips__)
typedef signed char int8_t ;
typedef unsigned char uint8_t ;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#else
#include <stdint.h>
#endif
#if defined(_WIN)
#define _STRUCT_PACK_
#ifndef __STD_CALL__
#define __STD_CALL__ __stdcall
#endif
#elif defined(__unix__)
#define _STRUCT_PACK_ __attribute__((packed))
#ifndef __STD_CALL__
#define __STD_CALL__
#endif
#elif defined(__linux__)
#define _STRUCT_PACK_ __attribute__((packed))
#ifndef __STD_CALL__
#define __STD_CALL__
#endif
#else
#define _STRUCT_PACK_ __attribute__((packed))
#ifndef __STD_CALL__
#define __STD_CALL__
#endif
#endif
#ifdef _REENTRANT_EX
#ifndef _REENTRANT
#define _REENTRANT
#endif
#endif
#if defined(_REENTRANT)
#ifndef _REENTRANT_MUTEX
#define _REENTRANT_MUTEX
#endif //_REENTRANT_MUTEX
#define _REENTRANT_BOOL_ 1
#else
#define _REENTRANT_BOOL_ 0
#endif //_REENTRANT
#ifdef _WIN
#pragma warning(disable:4503)
#pragma warning(disable:4786)
#pragma warning(disable:4996)
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4018)
#pragma warning(disable:4312)
#pragma warning(disable:4290)
#pragma warning(disable:4076)
/*/////////////////////////////////////////////////////////////////////////////
■ 4290 경고 : 함수 선언에 throw 가 있다.
warning C4290: 함수가 __declspec(nothrow)가 아님을 나타내려는 경우를 제외하고 C++ 예외 사양은 무시됩니다.
warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
-- 2013-07-08 02:39:00
■ 4076 경고 : wchar_t 에 unsigned 를 지정했다. 리눅스에서는 어떤 경고도 없다.
warning C4076: 'unsigned' : can not be used with type 'wchar_t'
-- 2013-07-08 02:45:00
/////////////////////////////////////////////////////////////////////////////*/
/*/////////////////////////////////////////////////////////////////////////////
■ WinSock2.h 파일이 include 되기 전에, windows.h 파일이 include 돼서는 안된다.
WinSock2.h 이 필요하면, 이 파일 MainHeader 보다 먼저 include 해야 한다.
■ TCHAR.H 파일을 include 하고 _MBCS 와 _UNICODE 가 정의되어 있으면
TCHAR 이 wchar_t 으로 정의되어야 하나, VC++ 6.0 에서는 자꾸 char 로 정의된다.
-- 2006-10-12 09:53:00
/////////////////////////////////////////////////////////////////////////////*/
#include <TCHAR.H>
#include <WinSock2.h>
#include <windows.h>
// 아래 pragma 코드가 이미 CNet_Win.H 에 있는데, 필요하면 아래 주석을 제거한다.
//
// #pragma comment(lib, "ws2_32")
#ifndef _T
#define _T(X) X
#endif
#if defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__<200000
// VC++ 6.0 에서는 아래 선언이 필요.
// VC++ 7.0 부터는 주석처리 할 것.
typedef unsigned long ULONG_PTR ;
typedef unsigned long* PULONG_PTR;
#endif //defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__<200000
#else // !defined(_WIN)
#include<errno.h>
#if defined(UNICODE) || defined(_UNICODE)
#define LPCTSTR const wchar_t*
#else
#define LPCTSTR const char*
#endif
#ifndef _T
#define _T(X) X
#endif
#define LONG long
#endif // !defined(_WIN)
#if defined(_REENTRANT)
#if defined(__linux__)
// 리눅스 Multi Thread Programming 에서 ZCObjList 라든가 여러
// 자료구조에서 쓰는 동기화 뮤텍스를 위해 pthread.h 를 포함한다.
#include <pthread.h>
#elif defined(__unix__)
#include <pthread.h>
#elif defined(__sun__) // In Solaris
#include <pthread.h>
#elif defined(_WIN)
//Don't inclucde
#else
#include <pthread.h>
#endif
#endif //defined(_REENTRANT)
#ifdef _DEBUG
#include<iostream>
#include<cstdlib>
#include<fstream>
#endif
using namespace std;
#define RR(RefReceive) RefReceive
// RR 메크로는 인수가 참조를 전달하고 다시 어떤 값으로 설정받는다는 것을 뜻함
#define _NP_
/* 템플릿의 멤버함수가 원래는 public 가 아니어야 하지만,
템플릿 설계상 어쩔 수 없이 public 으로 했음을 의미. No Public */
#define _VT_
// _VT_ 메크로는 주로 상속해서 사용하는 멤버함수를 의미
#define _SY_
/* 동기화(Sync) 영역에서 호출되는 함수를 의미. 따라서 이 함수안에서
같은 동기화 object 를 사용하는 함수를 호출하지 않도록 주의한다. */
#define _BETA_
/* beta 테스트 중이거나, 실제로 사용하기에는 기술적인 문제가
잠재해 있는 함수를 의미. (2011-04-03 21:37:00) */
#ifdef __CYGWIN__
#define atoll atol /*for Cygwin*/
#endif
#define __for0(IntType, i, LoopCount) for(IntType i=0; i< LoopCount; ++i)
#define __for1(IntType, i, LoopCount) for(IntType i=1; i<=LoopCount; ++i)
#define __forD0(i, LoopCount) for(i=0; i< LoopCount; ++i) // 정수형 선언이 미리 있는 경우. D 는 Declare.
#define __forD1(i, LoopCount) for(i=1; i<=LoopCount; ++i)
namespace ZNsMain
{
typedef int ZTypInt ;
typedef int ZTypIntE ; // int enum : 다른 enum 형끼리 비교할 일이 있을 때, 이 자료로 형변환한다.
typedef int ZTypIntEnum ;
typedef long ZTypIntLong ;
typedef short ZTypIntShort;
typedef int ZTypIntI ; // 정수를 가장 잘 대표할 수 있는 자료형. 필요에 따라 long 이나 short 으로 typedef 할 수도 있다.
typedef long ZTypIntL ;
typedef short ZTypIntS ;
typedef long ZTypLong ;
typedef short ZTypShort ;
typedef int8_t ZTypInt8 ;
typedef int16_t ZTypInt16 ;
typedef int32_t ZTypInt32 ;
typedef int64_t ZTypInt64 ;
typedef uint8_t ZTypUInt8 ;
typedef uint16_t ZTypUInt16 ;
typedef uint32_t ZTypUInt32 ;
typedef uint64_t ZTypUInt64 ;
typedef uint8_t ZTypIntU8 ;
typedef uint16_t ZTypIntU16 ;
typedef uint32_t ZTypIntU32 ;
typedef uint64_t ZTypIntU64 ;
#if defined(UNICODE) || defined(_UNICODE)
typedef wchar_t ZTypXCHAR ;
typedef wchar_t ZTypXChar ;
typedef wchar_t* ZTypXPChar ;
typedef const wchar_t* ZTypXCPChar ;
#else
typedef char ZTypXCHAR ;
typedef char ZTypXChar ;
typedef char* ZTypXPChar ;
typedef const char* ZTypXCPChar ;
#endif
typedef char ZTypChar ;
typedef wchar_t ZTypCharW ;
typedef const char ZTypCChar ;
typedef const wchar_t ZTypCCharW ;
typedef char* ZTypPChar ;
typedef const char* ZTypCPChar ;
typedef char* const ZTypPCChar ;
typedef const char* const ZTypCPCChar ;
typedef char* ZTypPCh ;
typedef const char* ZTypCPCh ;
typedef char* const ZTypPCCh ;
typedef const char* const ZTypCPCCh ;
typedef wchar_t* ZTypPWChar ;
typedef const wchar_t* ZTypCPWChar ;
typedef wchar_t* const ZTypPWCChar ;
typedef const wchar_t* const ZTypCPCWChar;
typedef wchar_t* ZTypPWCh ;
typedef const wchar_t* ZTypCPWCh ;
typedef wchar_t* const ZTypPWCCh ;
typedef const wchar_t* const ZTypCPCWCh ;
typedef unsigned char ZTypUChar ;
#if(0)
typedef unsigned wchar_t ZTypUWCha ;
/* VC++ 2012 에서는 여기서 4076 번 경고가 발생한다.
warning C4076: 'unsigned' : can not be used with type 'wchar_t'
Linux g++ 4.4.7 에서는 unsigned wchar_t 를 잘 인식하고 있다.
*/
#endif
typedef unsigned int ZTypUInt ;
typedef unsigned short ZTypUShort ;
typedef unsigned long ZTypULong ;
typedef unsigned char ZTypIntUChar ;
typedef unsigned int ZTypIntUInt ;
typedef unsigned short ZTypIntUShort ;
typedef unsigned long ZTypIntULong ;
typedef unsigned char ZTypIntUC ;
typedef unsigned int ZTypIntUI ;
typedef unsigned short ZTypIntUS ;
typedef unsigned long ZTypIntUL ;
#if(defined(__CPU_BIT_CNT__) && __CPU_BIT_CNT__>=64)
#ifdef _WIN
typedef __int64 ZTypLength ; // 문자열의 길이를 나타내는 자료형.
// 송수신 버퍼의 크기 자료형으로도 쓰인다.
#else
typedef long ZTypLength ;
#endif
#else // !defined(__CPU_BIT_CNT__) || __CPU_BIT_CNT__<64
typedef long ZTypLength ;
#endif // !defined(__CPU_BIT_CNT__) || __CPU_BIT_CNT__<64
#ifdef _WIN
typedef __int64 ZTypLengthFile; // 파일의 크기를 나타내는 자료형.
#else
typedef long ZTypLengthFile; // 파일의 크기를 나타내는 자료형.
#endif
typedef ZTypLengthFile ZTypLengthF;
#ifdef _WIN
typedef __int64 ZTypLongLong ;
typedef unsigned __int64 ZTypULongLong;
typedef __int64 ZTypIntLLong ;
typedef unsigned __int64 ZTypIntULLong;
#else
typedef long long ZTypLongLong ;
typedef unsigned long long ZTypULongLong;
typedef long long ZTypIntLLong ;
typedef unsigned long long ZTypIntULLong;
#endif
typedef ZTypLongLong ZTypLLong ;
typedef ZTypULongLong ZTypULLong;
typedef ZTypLongLong ZTypIntLL ;
typedef ZTypULongLong ZTypIntULL;
#ifdef _WIN64
typedef __int64 ZTypIntPtr ; // 포인터를 표현하는 정수 크기다.
typedef unsigned __int64 ZTypIntUPtr; // 포인터를 표현하는 양의 정수 크기다.
#else
typedef long ZTypIntPtr ;
typedef unsigned long ZTypIntUPtr;
#endif
#ifdef _WIN32
typedef HANDLE ZTypeID;
#else
typedef int ZTypeID;
#endif
typedef class ZCIterEasy{} IterEasy, *IterEasyID ;
typedef const IterEasyID* IterEasyIDc;
/*///////////////////////////////////////////////////////////////////////////////
■ typedef class CIterEasy{} *IterEasyID
CObjList<> 등에서 사용하는 반복자로 사용하는 자료형이다. 반복자를 사용할 때마
다, typedef typename std::CObjList<>::IterEasy IterEasy 등으로 길게 선언해야
하는 것이 성가셨다.
-- 2013-06-02 08:44:00
CObjList.H 등에서 관련 멤버 함수를 추가하고, CHttp.H 와 CHttp2.H 의 기존 ZCLink
를 사용하는 코드를 IterEasyID 을 사용하는 코드로 적절히 반영한 결과, 숨어 있던
버그를 발견하고 조치한 듯한, 맑은 기분을 느낄 수 있었다.
-- 2013-06-02 12:13:00
CStringEx.H 파일에도 반영했다. -- 2013-06-02 09:59:00
■ IterEasyIDc 선언을
typedef const IterEasyID IterEasyIDc;
라 하면, 천만 뜻밖에도 IterEasyIDc 의 type 이름(type().nmae() 으로 구한 값)이
IterEasyID 의 type 이름 값과 같다.
-- 2015-11-07 21:34:00
///////////////////////////////////////////////////////////////////////////////*/
class ZCEmpty
{
/*///////////////////////////////////////////////////////////////////////////
■ 템플릿 정의에서 비어있는 클래스를 요구하는 경우가 있다.
■ 또한 여러 개의 템플릿 인자를 가진 클래스 템플릿의 특정 인자에 대하여 부분
특수화를 하는 경우, 부분 특수화 되는 인수의 type 을, 특수화되지 않는 최초
의 템플릿 정의 부분에서 무엇으로 할 지 고민되는 경우가 있다면, 이때 고민
하지 말고 ZCEmpty 를 써버리자.
-- 2010-05-04 02:29:00
어, 근데 템플릿 인자에 void 를 사용할 수도 있다. 이것을 다소 늦게 알았는데,
그래도 비어 있는 클래스를 상속할 경우, 커파일러가 크기를 0 으로 해놓는 장점
이 있으니까 일단 그냥 둔다. 만약 void 를 사용하게 되면, void 를 템플릿 인자
로 사용하는 버전과 사용하지 않는 버전으로 항상 정의를 해주어야 하는 성가신
점이 있다.
-- 2012-09-01 17:26:00
///////////////////////////////////////////////////////////////////////////*/
};/*
class ZCEmpty*/
namespace ZNsInterface
{
// 이 이름공간안에 interface 가 되는 class (템플릿) 가 온다.
}/*
namespace ZNsInterface*/
namespace ZNsIFace
{
// 이름공간 ZNsInterface 을 짧게 ZNsIFace 으로도 표기 가능하게 한다.
using namespace ZNsInterface;
}/*
namespace ZNsIFace*/
namespace ZNsEnum
{
// ECompareResult 는 어떤 두 개의 값을 비교한 결과를 표시한다.
// GetCompareCode() 나 class ZZtCCompare<> 에서 사용할 것이다.
enum ZECompareResult
{
ZECompareResult_Equal= 0, // 서로 같다.
ZECompareResult_More = 1, // 왼쪽이 크다.
ZECompareResult_Less =-1 // 오른쪽이 크다.
};/*
enum ZECompareResult*/
}/*
namespace ZNsEnum*/
template<typename TTypeChar, typename TTypeLength> ZTypIntE GetCompareCode
(
const TTypeChar* ApcLeft , TTypeLength AI_LeftLength ,
const TTypeChar* ApcRight, TTypeLength AI_RightLength
)
/*######################################################################*/
{
if(AI_LeftLength<1 && AI_RightLength<1) return ZNsEnum::ZECompareResult_Equal;
TTypeLength ViLoopCnt= (AI_LeftLength<=AI_RightLength ? AI_LeftLength : AI_RightLength);
__for0(TTypeLength, i, ViLoopCnt)
{
if(ApcLeft[i] > ApcRight[i]) return ZNsEnum::ZECompareResult_More;
if(ApcLeft[i] < ApcRight[i]) return ZNsEnum::ZECompareResult_Less;
}/*
__for0(TTypeLength, i, ViLoopCnt)*/
if(AI_LeftLength==AI_RightLength) return ZNsEnum::ZECompareResult_Equal;
if(AI_LeftLength> AI_RightLength) return ZNsEnum::ZECompareResult_More ;
if(AI_LeftLength< AI_RightLength) return ZNsEnum::ZECompareResult_Less ;
return ZNsEnum::ZECompareResult_Equal;
}/*
template<typename TTypeChar, typename TTypeLength> ZTypIntE GetCompareCode
(
const TTypeChar* ApcLeft , TTypeLength AI_LeftLength,
const TTypeChar* ApcRight, TTypeLength AI_RightLength
)
########################################################################*/
/* 어떤 변수를 강제적으로 참조로 인식하게 하는 클래스. 인수를 참조로
넘어가게 하고 싶을 때 사용한다. class ZtCCheckRef 에서 사용하고 있다.
-- 2021-04-10 16:15
*/
template<typename TType> class ZtCRef
{
public :
typedef TType& TypeData;
typedef TType TypeRaw ;
private:
TypeData mr_Data;
public :
ZtCRef(TypeData AR_TypeData) : mr_Data(AR_TypeData){}
public :
TypeData GetData(){return mr_Data;}
};/*
template<typename TType> class ZtCRef*/
/* template 인수에 ZtCRef 가 있으면, 해당 값을 참조로 인식하고
그렇지 않으면, 일반적인 복사해서 전달되는 값으로 인식한다.
ZtCArray.H 같은 자료 구조에서 사용하고 있다.
-- 2021-04-10 16:15
*/
template<typename TType> class ZtCCheckRef
{
public :
typedef TType TypeData;
typedef TType TypeRaw ;
private:
TypeData mr_Data;
public :
ZtCCheckRef(TypeData AR_TypeData) : mr_Data(AR_TypeData){}
public :
TypeData GetData(){return mr_Data;}
public :
static TypeData PassData(TypeData AO_Data){return AO_Data;}
};/*
template<typename TType> class ZtCCheckRef*/
/* ZtCRef 전문화 */
template<typename TType> class ZtCCheckRef< ZtCRef<TType> >
{
public :
typedef TType& TypeData;
typedef TType TypeRaw ;
typedef ZtCRef<TType> ZCRef ;
private:
TypeData mr_Data;
public :
ZtCCheckRef(TypeData AR_TypeData) : mr_Data(AR_TypeData){}
public :
TypeData GetData(){return mr_Data;}
public :
static TypeData PassData(TypeData AO_Data){return AO_Data;}
static TypeData PassData(ZCRef& AO_Data){return AO_Data.GetData();}
static TypeData PassData(const ZCRef& AO_Data)
{return (const_cast<ZCRef>(AO_Data)).GetData();}
};/*
template<typename TType> class ZtCCheckRef< ZtCRef<TType> >*/
namespace ZNsType
{
/*/////////////////////////////////////////////////////////////////////////////////////////
■ (주로 클래스) 템플릿에는 typename 인수를 10 개 이상 요구하는 복잡한 템플릿이 있는데 이런
템플릿의 typename 을 미리 예를 들어 명시함으로서 그 템플릿의 typename 을 지정하기 쉽도록
가이드라인을 제시하는 역할의 어떤 클래스나 데이타 타입이 올 수 있는데 이런 자료형이 이
이름공간에 온다. 어떤 데이타타입을 주로 typedef 하는 클래스라면 접두어 ZtCType 를 붙인다.
■ ZtCTypeCRTP<> 는 어떤 클래스 템플릿이 CRTP(CURIOUSLY RECURRING TEMPLATE PATTERN) 를 사용
하는지 아닌지를 알려준다. ZtCTypeCRTP<> 을 설계하지 않는다면, 같은 기능을 하기 위해, 클
래스를 2 개(CRTP 를 사용하는 클래스와, 그렇지 않은 클래스)를 만들어야 했을 것이다.
-- 2010-03-12 20:00:00
class ZtCTypeCRTP 는 상속 클래스만을 표시하고,
class ZtCTypeCRTP2_T 는 상속 클래스와 기반 클래스 모두를 표시한다.
어쩌면 모든 상속 클래스는 내부적으로, ZtCTypeCRTP 클래스를 갖는 원칙을 세우는 것도 좋겠
다. 그래서 상속 클래스가 CDerive0 라면, 기반 클래스에 접근하고 싶을 때,
CDerive0::ZtCTypeCRTP::TypeData
형식으로 일관성있게 접근하도록 하는 것이다. 그러자면 다중 상속의 경우에 문제가 있겠네.
-- 2021-03-25 16:01
■ 또한 이 이름 공간에 있는 클래스는 TypeData 라는 자료형을 갖는 것으로 하자.
-- 2011-10-18 21:51:00
/////////////////////////////////////////////////////////////////////////////////////////*/
template< typename TTypeChild=ZCEmpty, bool TTypebUseCRTP =false
>
class ZtCTypeCRTP ////////////////////////////////////////////////
{
public:
typedef TTypeChild TypeData;
public:
enum{ZEUseCRTP=(ZTypIntE)TTypebUseCRTP};
public:
};/*
template< typename TTypeChild=ZCEmpty, bool TTypebUseCRTP =false
>
class ZtCTypeCRTP //////////////////////////////////////////////*/
template< typename TTypeChild =ZCEmpty
, typename TTypeBase =ZCEmpty
, bool TTypebUseCRTP=false
>
class ZtCTypeCRTP2_T /////////////////////
{
public:
typedef TTypeChild TypeData;
typedef TTypeBase TypeBase;
public:
enum{ZEUseCRTP=(ZTypIntE)TTypebUseCRTP};
public:
}; /*
template< typename TTypeChild =ZCEmpty
, typename TTypeBase =ZCEmpty
, bool TTypebUseCRTP=false
>
class ZtCTypeCRTP2 /////////////////////*/
/*//////////////////////////////////////////////////////////////////////////////////////////
■ class ZtCTypeCRTP2<> 이 왜 필요한지, 그리고 사용례는 예전 파일 CWorkPool.H 의
'주석-CCtrlAllocWork::CRTP2'를 참고한다.
-- 2012-09-20 09:46:00
//////////////////////////////////////////////////////////////////////////////////////////*/
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////
■ class ZtCTypeCRTP<> 의 단점은 상속하지 않은 class 형은 알 수 없는데, 이것을 알아내기 위해
class ZtCTypeNowCRTP<>
을 설계한다. 이 클래스의 사용예는 예전 파일 CCtrlAsyncSock.H 에 있었다.
아래 코드에서 TAsyncServ 의 상속 클래스가
없다면, CMainServ 는 TAsyncServ 과 같고,
있다면, CMainServ0 가 상속 클래스
가 된다.
typedef typename TAsyncServ::ZtCTypeCRTP ZtCTypeCRTP ;
typedef typename ZtCTypeCRTP ::TypeData CMainServ0;
typedef std::ZNsType::ZtCTypeNowCRTP<
TAsyncServ, CMainServ0>::TypeData CMainServ ;
CMainServ& VR_CMainServ=
static_cast<CMainServ&>(ArCAsyncServ);
ZtCTypeNowCRTP<> 이 없었을 때에는 TAsyncServ 이 상속 클래스를 갖지 않은 경우, CMainServ0 이 ZCEmpty 가 되어서,
컴파일 에러를 피하기가 매우 복잡한 경우가 있었다. 지금은 상속 클래스가 없다면 그냥 자기 자신의 인터페이스를
사용하니까 컴파일 에러가 전혀 없다.
정말 멋진 기교가 아닌가. C++ 의 향기에 잠시 취해 보자. -- 2013-06-10 00:33:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template<typename TTypeNow, typename TTypeChild>
class ZtCTypeNowCRTP
{ public: typedef TTypeChild TypeData; public: enum{ZEUseCRTP=1}; };
template<typename TTypeNow>
class ZtCTypeNowCRTP<TTypeNow, ZCEmpty>
{ public: typedef TTypeNow TypeData; public: enum{ZEUseCRTP=0}; };
template<typename TTypeNow>
class ZtCTypeNowCRTP<TTypeNow, void >
{ public: typedef TTypeNow TypeData; public: enum{ZEUseCRTP=0}; };
/* template 인수에 ZtCRef 가 있으면, 해당 값을 참조로 인식하고
그렇지 않으면, 일반적인 복사로 전달되는 값으로 인식한다.
class ZtCCheckRef 와는 달리, 멤버 변수를 갖지 않고, 순수하게
typedef 만 있다.
-- 2021-04-10 16:15
*/
template<typename TType> class ZtCTypeCheckRef
{
public :
typedef TType TypeData;
typedef TType TypeRaw ;
public :
};/*
template<typename TType> class ZtCTypeCheckRef*/
template<typename TType> class ZtCTypeCheckRef< ZtCRef<TType> >
{
public :
typedef TType& TypeData;
typedef TType TypeRaw ;
typedef ZtCRef<TType> ZCRef ;
public :
};/*
template<typename TType> class ZtCTypeCheckRef< ZtCRef<TType> >*/
namespace ZNsTmplParam
{
/*//////////////////////////////////////////////////////////////////////////
■ 이 이름 공간에는 어떤 템플릿의 인수가 많고, 이 인수가 몇 개의 인수가 기본
값을 갖는 경우, 끝 부분에 있는 기본값 정의 인수에 명시적인 자료형을 지정
해야 할 때, 그 이전의 기본 인수에 대해서도 일일이 지정을 해야 하는데, 이
런 불편을 일부 덜기 위해서 기본값 정의 순서가 다른 template 을 설계한다.
여기에 놓이는 클래스는 CParam~ 으로 시작하자.
■ ZNsTmplParam 이름공간은 꼭 ZNsType 에만 있을 필요는 없다. 그보다 더 적절한
장소가 있다면 그 곳에 선언하자.
//////////////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsTmplParam*/
/*//////////////////////////////////////////////////////////////////////////////
■ class ZtCTypeArguBind 은 class ZtCArguBind 에서 사용된다.
class ZtCTypeArguBind 와 class ZtCArguBind 의 사용예는 CArguBind_test.cpp 에
있다.
ZtCArguBind 은 boost 의 bind 를 흉내낸 것인데, 용법은 좀 다르다.
-- 2014-07-05 18:49:00
//////////////////////////////////////////////////////////////////////////////*/
template< typename TTypeArgu1 , typename TTypeArgu2
, typename TTypeArgu3=ZCEmpty, typename TTypeArgu4 =ZCEmpty
, typename TTypeArgu5=ZCEmpty, typename TTypeArgu6 =ZCEmpty
, typename TTypeArgu7=ZCEmpty, typename TTypeArgu8 =ZCEmpty
, typename TTypeArgu9=ZCEmpty, typename TTypeArgu10=ZCEmpty
>
class ZtCTypeArguBind ///////////////////////////////////////////////
{
public:
typedef typename ZtCTypeCheckRef<TTypeArgu1 >::TypeData TypeArgu1 ;
typedef typename ZtCTypeCheckRef<TTypeArgu2 >::TypeData TypeArgu2 ;
typedef typename ZtCTypeCheckRef<TTypeArgu3 >::TypeData TypeArgu3 ;
typedef typename ZtCTypeCheckRef<TTypeArgu4 >::TypeData TypeArgu4 ;
typedef typename ZtCTypeCheckRef<TTypeArgu5 >::TypeData TypeArgu5 ;
typedef typename ZtCTypeCheckRef<TTypeArgu6 >::TypeData TypeArgu6 ;
typedef typename ZtCTypeCheckRef<TTypeArgu7 >::TypeData TypeArgu7 ;
typedef typename ZtCTypeCheckRef<TTypeArgu8 >::TypeData TypeArgu8 ;
typedef typename ZtCTypeCheckRef<TTypeArgu9 >::TypeData TypeArgu9 ;
typedef typename ZtCTypeCheckRef<TTypeArgu10>::TypeData TypeArgu10;
struct ZStArguments2{ ZStArguments2(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2):
_1(AR_TypeArgu1), _2(AR_TypeArgu2){}
TypeArgu1 _1; TypeArgu2 _2;
};/*
struct ZStArguments2*/
struct ZStArguments3{ZStArguments3(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3;
};/*
struct ZStArguments3*/
struct ZStArguments4{ZStArguments4(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3, TypeArgu4 AR_TypeArgu4):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3), _4(AR_TypeArgu4){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3; TypeArgu4 _4;
};/*
struct ZStArguments4*/
struct ZStArguments5{ZStArguments5(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3, TypeArgu4 AR_TypeArgu4, TypeArgu5 AR_TypeArgu5):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3), _4(AR_TypeArgu4), _5(AR_TypeArgu5){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3; TypeArgu4 _4; TypeArgu5 _5;
};/*
struct ZStArguments5*/
struct ZStArguments6{ZStArguments6(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3, TypeArgu4 AR_TypeArgu4, TypeArgu5 AR_TypeArgu5, TypeArgu6 AR_TypeArgu6):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3), _4(AR_TypeArgu4), _5(AR_TypeArgu5), _6(AR_TypeArgu6){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3; TypeArgu4 _4; TypeArgu5 _5; TypeArgu6 _6;
};/*
struct ZStArguments6*/
struct ZStArguments7{ZStArguments7(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3, TypeArgu4 AR_TypeArgu4, TypeArgu5 AR_TypeArgu5, TypeArgu6 AR_TypeArgu6, TypeArgu7& AR_TypeArgu7):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3), _4(AR_TypeArgu4), _5(AR_TypeArgu5), _6(AR_TypeArgu6), _7(AR_TypeArgu7){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3; TypeArgu4 _4; TypeArgu5 _5; TypeArgu6 _6; TypeArgu7 _7;
};/*
struct ZStArguments7*/
struct ZStArguments8{ZStArguments8(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3, TypeArgu4 AR_TypeArgu4, TypeArgu5 AR_TypeArgu5, TypeArgu6 AR_TypeArgu6, TypeArgu7& AR_TypeArgu7, TypeArgu8& AR_TypeArgu8):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3), _4(AR_TypeArgu4), _5(AR_TypeArgu5), _6(AR_TypeArgu6), _7(AR_TypeArgu7), _8(AR_TypeArgu8){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3; TypeArgu4 _4; TypeArgu5 _5; TypeArgu6 _6; TypeArgu7 _7; TypeArgu8 _8;
};/*
struct ZStArguments8*/
struct ZStArguments9{ZStArguments9(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3, TypeArgu4 AR_TypeArgu4, TypeArgu5 AR_TypeArgu5, TypeArgu6 AR_TypeArgu6, TypeArgu7& AR_TypeArgu7, TypeArgu8& AR_TypeArgu8, TypeArgu9 AR_TypeArgu9):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3), _4(AR_TypeArgu4), _5(AR_TypeArgu5), _6(AR_TypeArgu6), _7(AR_TypeArgu7), _8(AR_TypeArgu8), _9(AR_TypeArgu9){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3; TypeArgu4 _4; TypeArgu5 _5; TypeArgu6 _6; TypeArgu7 _7; TypeArgu8 _8; TypeArgu9 _9;
};/*
struct ZStArguments9*/
struct ZStArguments10{ZStArguments10(
TypeArgu1 AR_TypeArgu1, TypeArgu2 AR_TypeArgu2, TypeArgu3 AR_TypeArgu3, TypeArgu4 AR_TypeArgu4, TypeArgu5 AR_TypeArgu5, TypeArgu6 AR_TypeArgu6, TypeArgu7& AR_TypeArgu7, TypeArgu8& AR_TypeArgu8, TypeArgu9 AR_TypeArgu9, TypeArgu10 AR_TypeArgu10):
_1(AR_TypeArgu1), _2(AR_TypeArgu2), _3(AR_TypeArgu3), _4(AR_TypeArgu4), _5(AR_TypeArgu5), _6(AR_TypeArgu6), _7(AR_TypeArgu7), _8(AR_TypeArgu8), _9(AR_TypeArgu9), _10(AR_TypeArgu10){}
TypeArgu1 _1; TypeArgu2 _2; TypeArgu3 _3; TypeArgu4 _4; TypeArgu5 _5; TypeArgu6 _6; TypeArgu7 _7; TypeArgu8 _8; TypeArgu9 _9; TypeArgu10 _10;
};/*
struct ZStArguments10*/
public:
};/*
template< typename TTypeArgu1 , typename TTypeArgu2
, typename TTypeArgu3=ZCEmpty, typename TTypeArgu4 =ZCEmpty
, typename TTypeArgu5=ZCEmpty, typename TTypeArgu6 =ZCEmpty
, typename TTypeArgu7=ZCEmpty, typename TTypeArgu8 =ZCEmpty
, typename TTypeArgu9=ZCEmpty, typename TTypeArgu10=ZCEmpty
>
class ZtCTypeArguBind /////////////////////////////////////////////*/
}/*
namespace ZNsType*/
template<typename TClassExec> class ZtCArguBind
{
public:
template<typename Type1, typename Type2>
static void Exec2(Type1& AR_Type1, Type2& AR_Type2)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2>::
ZStArguments2 VO_ZtCTypeArguBind(AR_Type1, AR_Type2);
TClassExec::Exec2(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2>
static void Exec2(Type1& AR_Type1, Type2& AR_Type2)*/
template<typename Type1, typename Type2, typename THelpType>
static void Exec2(Type1& AR_Type1, Type2& AR_Type2, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2>::
ZStArguments2 VO_ZtCTypeArguBind(AR_Type1, AR_Type2);
TClassExec::Exec2(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename THelpType>
static void Exec2(Type1& AR_Type1, Type2& AR_Type2, THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3>
static void Exec3(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3>::
ZStArguments3 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3);
TClassExec::Exec3(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3>
static void Exec3(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3)*/
template<typename Type1, typename Type2, typename Type3, typename THelpType>
static void Exec3(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3>::
ZStArguments3 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3);
TClassExec::Exec4(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename THelpType>
static void Exec3(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3, typename Type4>
static void Exec4(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4>::
ZStArguments4 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4);
TClassExec::Exec4(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4>
static void Exec4(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename THelpType>
static void Exec4(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4>::
ZStArguments4 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4);
TClassExec::Exec4(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename THelpType>
static void Exec4(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5>
static void Exec5(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5>::
ZStArguments5 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5);
TClassExec::Exec5(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5>
static void Exec5(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename THelpType>
static void Exec5(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5>::
ZStArguments5 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5);
TClassExec::Exec5(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename THelpType>
static void Exec5(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6>
static void Exec6(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6>::
ZStArguments6 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6);
TClassExec::Exec6(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6>
static void Exec6(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename THelpType>
static void Exec6(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6>::
ZStArguments6 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6);
TClassExec::Exec6(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename THelpType>
static void Exec6(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7>
static void Exec7(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7>::
ZStArguments7 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type6, AR_Type7);
TClassExec::Exec7(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7>
static void Exec7(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename THelpType>
static void Exec7(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7>::
ZStArguments7 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type7);
TClassExec::Exec7(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename THelpType>
static void Exec7(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7 THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8>
static void Exec8(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8>::
ZStArguments8 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type6, AR_Type7, AR_Type8);
TClassExec::Exec8(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8>
static void Exec8(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename THelpType>
static void Exec8(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8>::
ZStArguments8 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type7, AR_Type8);
TClassExec::Exec8(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename THelpType>
static void Exec8(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9>
static void Exec9(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9>::
ZStArguments9 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type6, AR_Type7, AR_Type8, AR_Type9);
TClassExec::Exec9(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9>
static void Exec9(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename THelpType>
static void Exec9(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9>::
ZStArguments9 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type7, AR_Type8, AR_Type9);
TClassExec::Exec9(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename THelpType>
static void Exec9(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9, THelpType& ArHelpType)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10>
static void Exec10(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9, Type10& AR_Type10)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10>::
ZStArguments10 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type6, AR_Type7, AR_Type8, AR_Type9, AR_Type10);
TClassExec::Exec10(VO_ZtCTypeArguBind);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10>
static void Exec10(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9, Type10& AR_Type10)*/
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10, typename THelpType>
static void Exec10(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9, Type10& AR_Type10, THelpType& ArHelpType)
{
typename ZNsType::ZtCTypeArguBind<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10>::
ZStArguments10 VO_ZtCTypeArguBind(AR_Type1, AR_Type2, AR_Type3, AR_Type4, AR_Type5, AR_Type6, AR_Type7, AR_Type8, AR_Type9, AR_Type10);
TClassExec::Exec10(VO_ZtCTypeArguBind, ArHelpType);
}/*
template<typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10, typename THelpType>
static void Exec10(Type1& AR_Type1, Type2& AR_Type2, Type3& AR_Type3, Type4& AR_Type4, Type5& AR_Type5, Type6& AR_Type6, Type7& AR_Type7, Type8& AR_Type8, Type9& AR_Type9, Type10& AR_Type10, THelpType& ArHelpType)*/
public:
};/*
template<typename TClassExec> class ZtCArguBind*/
/*//////////////////////////////////////////////////////////////////////////////////////////
■ 위 ZtCArguBind<> 보다는 아래 struct ZtStTuple<> 이 더 유용할 것이다. -- 2015-02-15 20:52:00
■ template 인수가 Type11 까지 있음에 주의한다. 그러면 Type10 까지 전문화할 수 있는 것이다.
-- 2015-02-16 21:20:00
단, template 인수는 2개부터가 유효하다.
typedef ZtStTuple<int> CTupleInt1 는 오류다.
typedef ZtStTuple<int, int> CTupleInt2 는 정상이다.
상식적으로도 ZtStTuple<int> 으로 쓸 일은 없다. -- 2021-03-04 16:27
//////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1 , typename Type2 =void,
typename Type3=void, typename Type4 =void,
typename Type5=void, typename Type6 =void,
typename Type7=void, typename Type8 =void,
typename Type9=void, typename Type10=void, typename Type11=void
>
struct ZtStTuple //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
Type1 _1;
ZtStTuple(){}
ZtStTuple(Type1 _T1):_1(_T1){}
};/*
template< typename Type1 , typename Type2 =void,
typename Type3=void, typename Type4 =void,
typename Type5=void, typename Type6 =void,
typename Type7=void, typename Type8 =void,
typename Type9=void, typename Type10=void, typename Type11=void
>
struct ZtStTuple ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2> ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
TypeData1 _1; TypeData2 _2;
ZtStTuple<Type1, Type2>(){}
ZtStTuple<Type1, Type2>(
TypeData1 _T1, TypeData2 _T2) : _1(_T1), _2(_T2) {}
};/*
template< typename Type1, typename Type2 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
TypeData1 _1; TypeData2 _2; TypeData3 _3;
ZtStTuple<Type1, Type2, Type3>(){}
ZtStTuple<Type1, Type2, Type3>(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3) :
_1(_T1), _2(_T2), _3(_T3){}
};/*
template< typename Type1, typename Type2, typename Type3 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3> ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3, typename Type4 ////////////////////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4;
ZtStTuple<Type1, Type2, Type3, Type4>(){}
ZtStTuple<Type1, Type2, Type3, Type4>(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4) :
_1(_T1), _2(_T2), _3(_T3), _4(_T4) {}
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4 ////////////////////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4> ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5 ////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5> ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4; TypeData5 _5;
ZtStTuple<Type1, Type2, Type3, Type4, Type5>(){}
ZtStTuple<Type1, Type2, Type3, Type4, Type5>(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4, TypeData5 _T5) :
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5){}
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5 ////////////////////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6 ////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6> ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
TypeData1 _1; TypeData2 _2; TypeData3 _3;
TypeData4 _4; TypeData5 _5; TypeData6 _6;
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6>(){}
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6>(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3 ,
TypeData4 _T4, TypeData5 _T5, TypeData6 _T6) :
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5), _6(_T6) {}
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6 ////////////////////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7 ////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData TypeData7 ;
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4;
TypeData5 _5; TypeData6 _6; TypeData7 _7;
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7>(){}
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7>(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4,
TypeData5 _T5, TypeData6 _T6, TypeData7 _T7) :
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5), _6(_T6), _7(_T7) {}
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7 ////////////////////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7> ///////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8 ////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8> //////////////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData TypeData7 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type8>::TypeData TypeData8 ;
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4;
TypeData5 _5; TypeData6 _6; TypeData7 _7; TypeData8 _8;
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8>(){}
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8>(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4,
TypeData5 _T5, TypeData6 _T6, TypeData7 _T7, TypeData8 _T8) :
_1(_T1), _2(_T2), _3(_T3), _4(_T4) ,
_5(_T5), _6(_T6), _7(_T7), _8(_T8) {}
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8 ////////////////////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8> ////////////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9 ////////////////////////
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9> ///////////////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData TypeData3 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData TypeData4 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData TypeData5 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData TypeData6 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData TypeData7 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type8>::TypeData TypeData8 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type9>::TypeData TypeData9 ;
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4; TypeData5 _5;
TypeData6 _6; TypeData7 _7; TypeData8 _8; TypeData9 _9;
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9>(){}
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9>
(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4,
TypeData5 _T5, TypeData6 _T6, TypeData7 _T7, TypeData8 _T8, TypeData9 _T9
) :
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5(_T5),
_6(_T6), _7(_T7), _8(_T8), _9(_T9) {}
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9> /////////////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10> ///////////////////////////////////////////////////////////////////////////////////////////
{
typedef typename ZNsType::ZtCTypeCheckRef<Type1 >::TypeData TypeData1 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type2 >::TypeData TypeData2 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type3 >::TypeData TypeData3 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type4 >::TypeData TypeData4 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type5 >::TypeData TypeData5 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type6 >::TypeData TypeData6 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type7 >::TypeData TypeData7 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type8 >::TypeData TypeData8 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type9 >::TypeData TypeData9 ;
typedef typename ZNsType::ZtCTypeCheckRef<Type10>::TypeData TypeData10;
TypeData1 _1; TypeData2 _2; TypeData3 _3; TypeData4 _4; TypeData5 _5 ;
TypeData6 _6; TypeData7 _7; TypeData8 _8; TypeData9 _9; TypeData9 _10;
ZtStTuple<
Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10>(){}
ZtStTuple<
Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10>(
TypeData1 _T1, TypeData2 _T2, TypeData3 _T3, TypeData4 _T4, TypeData5 _T5 ,
TypeData6 _T6, TypeData7 _T7, TypeData8 _T8, TypeData9 _T9, TypeData10 _T10) :
_1(_T1), _2(_T2), _3(_T3), _4(_T4), _5 (_T5 ),
_6(_T6), _7(_T7), _8(_T8), _9(_T9), _10(_T10) {}
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10
>
struct ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10> /////////////////////////////////////////////////////////////////////////////////////////*/
template< typename Type1, typename Type2
>
ZtStTuple<Type1, Type2> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2
)
{
return ZtStTuple<Type1, Type2>(AO_Type1, AO_Type2);
};/*
template< typename Type1, typename Type2
>
ZtStTuple<Type1, Type2> ZftMakeArguTuple(Type1 AO_Type1, Type2 AO_Type2) */
template< typename Type1, typename Type2, typename Type3
>
ZtStTuple<Type1, Type2, Type3> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData AO_Type3
)
{
return ZtStTuple<Type1, Type2, Type3>(AO_Type1, AO_Type2, AO_Type3);
};/*
template< typename Type1, typename Type2, typename Type3
>
ZtStTuple<Type1, Type2, Type3> ZftMakeArguTuple(Type1 AO_Type1, Type2 AO_Type2, Type2 AO_Type3) */
template< typename Type1, typename Type2, typename Type3, typename Type4
>
ZtStTuple<Type1, Type2, Type3, Type4> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData AO_Type3,
typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData AO_Type4
)
{
return ZtStTuple<Type1, Type2, Type3, Type4>
(AO_Type1, AO_Type2, AO_Type3, AO_Type4);
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4
>
ZtStTuple<Type1, Type2, Type3, Type4> ZftMakeArguTuple(Type1 AO_Type1, Type2 AO_Type2, Type3 AO_Type3, Type4 AO_Type4) */
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData AO_Type3,
typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData AO_Type4,
typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData AO_Type5
)
{
return ZtStTuple<Type1, Type2, Type3, Type4, Type5>
(AO_Type1, AO_Type2, AO_Type3, AO_Type4, AO_Type5);
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5> ZftMakeArguTuple(Type1 AO_Type1, Type2 AO_Type2, Type3 AO_Type3, Type4 AO_Type4, Type5 AO_Type5) */
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData AO_Type3,
typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData AO_Type4,
typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData AO_Type5,
typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData AO_Type6
)
{
return ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6>
(AO_Type1, AO_Type2, AO_Type3, AO_Type4, AO_Type5, AO_Type6);
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6> ZftMakeArguTuple(Type1 AO_Type1, Type2 AO_Type2, Type3 AO_Type3, Type4 AO_Type4, Type5 AO_Type5, Type6AO_Type6) */
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData AO_Type3,
typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData AO_Type4,
typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData AO_Type5,
typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData AO_Type6,
typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData AO_Type7
)
{
return ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7>
(AO_Type1, AO_Type2, AO_Type3, AO_Type4, AO_Type5, AO_Type6, AO_Type7);
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, typename Type7> ZftMakeArguTuple(Type1 AO_Type1, Type2 AO_Type2, Type3 AO_Type3, Type4 AO_Type4, Type5 AO_Type5, Type6 AO_Type6, Type7 AO_Type7) */
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData AO_Type3,
typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData AO_Type4,
typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData AO_Type5,
typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData AO_Type6,
typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData AO_Type7,
typename ZNsType::ZtCTypeCheckRef<Type8>::TypeData AO_Type8
)
{
return ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8>
(AO_Type1, AO_Type2, AO_Type3, AO_Type4, AO_Type5, AO_Type6, AO_Type7, AO_Type8);
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8> ZftMakeArguTuple(
Type1 AO_Type1, Type2 AO_Type2, Type3 AO_Type3, Type4 AO_Type4, Type5 AO_Type5, Type6 AO_Type6, Type7 AO_Type7, Type8 AO_Type8) */
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1>::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2>::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3>::TypeData AO_Type3,
typename ZNsType::ZtCTypeCheckRef<Type4>::TypeData AO_Type4,
typename ZNsType::ZtCTypeCheckRef<Type5>::TypeData AO_Type5,
typename ZNsType::ZtCTypeCheckRef<Type6>::TypeData AO_Type6,
typename ZNsType::ZtCTypeCheckRef<Type7>::TypeData AO_Type7,
typename ZNsType::ZtCTypeCheckRef<Type8>::TypeData AO_Type8,
typename ZNsType::ZtCTypeCheckRef<Type9>::TypeData AO_Type9
)
{
return ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9>
(AO_Type1, AO_Type2, AO_Type3, AO_Type4, AO_Type5, AO_Type6, AO_Type7, AO_Type8, AO_Type9);
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9> ZftMakeArguTuple(
Type1 AO_Type1, Type2 AO_Type2, Type3 AO_Type3, Type4 AO_Type4, Type5 AO_Type5, Type6 AO_Type6, Type7 AO_Type7, Type8 AO_Type8, Type8 AO_Type9) */
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10> ZftMakeArguTuple
(
typename ZNsType::ZtCTypeCheckRef<Type1 >::TypeData AO_Type1,
typename ZNsType::ZtCTypeCheckRef<Type2 >::TypeData AO_Type2,
typename ZNsType::ZtCTypeCheckRef<Type3 >::TypeData AO_Type3,
typename ZNsType::ZtCTypeCheckRef<Type4 >::TypeData AO_Type4,
typename ZNsType::ZtCTypeCheckRef<Type5 >::TypeData AO_Type5,
typename ZNsType::ZtCTypeCheckRef<Type6 >::TypeData AO_Type6,
typename ZNsType::ZtCTypeCheckRef<Type7 >::TypeData AO_Type7,
typename ZNsType::ZtCTypeCheckRef<Type8 >::TypeData AO_Type8,
typename ZNsType::ZtCTypeCheckRef<Type9 >::TypeData AO_Type9,
typename ZNsType::ZtCTypeCheckRef<Type10>::TypeData AO_Type10
)
{
return ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10>
(AO_Type1, AO_Type2, AO_Type3, AO_Type4, AO_Type5, AO_Type6, AO_Type7, AO_Type8, AO_Type9, AO_Type10);
};/*
template< typename Type1, typename Type2, typename Type3, typename Type4, typename Type5, typename Type6, typename Type7, typename Type8, typename Type9, typename Type10
>
ZtStTuple<Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10> ZftMakeArguTuple(
Type1 AO_Type1, Type2 AO_Type2, Type3 AO_Type3, Type4 AO_Type4, Type5 AO_Type5, Type6 AO_Type6, Type7 AO_Type7, Type8 AO_Type8, Type9 AO_Type9, Type1 AO_Type10) */
namespace ZNsHide
{
/* 특정 클래스 안에서만 사용되어, 사용자가 그 존재를 알 필요가 없는 클래스를 둔다. */
}/*
namespace ZNsHide*/
namespace ZNsIn
{
/*///////////////////////////////////////////////////////////////////////////////
■ 특정 메인 클래스에 종속되어 사용되는 클래스가 있고, 메인 클래스가 생성될 때 등,
아주 잠시만 필요한 클래스가 있다면 ZNsIn~ 접두어로 시작하는 namespace 에 둔다.
ZNsHide 에 두자니 한 번은 명시적으로 사용을 하니까 Hidden 되지는 않기 때문에,
이렇게 하자. 이를테면 CIocp 클래스가 있는데, 이 클래스의 생성자에서 CHelpIocp
클래스를 인수로 받고, 그 후 CHelpIocp 는 사용자가 직접 사용할 일이 없다면 이 클
래스는 namespace ZNsInIOCP 에 둘 수 있겠다.
-- 2009-12-21 12:56:00
///////////////////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsIn*/
namespace ZNsTmplParam
{
}/*
namespace ZNsTmplParam*/
namespace ZNsBase
{
// 가상클래스도 아니고 인터페이스 전용의 함수도 아니면서
// 주로 기반 클래스로 사용되는 클래스는 여기에 둔다.
}/*
namespace ZNsBase*/
namespace ZNsSngt
{
/*////////////////////////////////////////////////////////////////////////////////////////////
■ singleton 으로 사용되는 object 들을 가져오는 함수나 object 들은 여기에 둔다.
singleton 으로 사용되는 object 들은 여기에 두지말고, CSngt 라는 접두어를 사용할 수도 있다.
////////////////////////////////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsSngt*/
namespace ZNsSttc
{
/*/////////////////////////////////////////////////////////////////////////////
■ static 멤버만을 갖는 object 들은 여기에 두거나 CSttc 라는 접두어를 사용한다.
-- 2010-03-10 19:58:00
/////////////////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsSttc*/
namespace ZNsReent
{
/*////////////////////////////////////////////////////////////
■ ZNsReent : namespace Reentrant
어떤 자료 구조가 thread safe 한 경우와, 그렇지 않은 경우를
따로 구현한다면 thread safe 한 구조를 여기에 둔다.
////////////////////////////////////////////////////////////*/
}/*
namespace ZNsReent*/
namespace ZNsArg
{
/*////////////////////////////////////////////////////////////////
■ 쓰레드의 Call Back 함수와 같이 어떤 함수가 특정한 자료를 포인터
로 받고 있는데, 이 포인터가 특수한 사정으로 여러 자료형의 object
의 포인터를 받아야 할 때, 해당 object 들의 포인터를 class 로 묶
고 이 클래스 object 의 포인터로 사용하면 되는데, 이와 같은 용도
로 사용하는 클래스는 여기에 둔다.
쓰레드의 Call Back 함수라면 아예 그 함수 내부에서 내포 클래스로
정의해버리는 것이 더 좋을 것 같다.
-- 2010-01-02 22:11:00
////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsArg*/
namespace ZNsDeco
{
/*////////////////////////////////////////////////////////////////
■ 어떤 클래스(템플릿)이 거의 같은 기능을 하지만, Decoration 패턴
을 사용하는 클래스와, 그렇지 않은 클래스가 쌍으로 존재할 때,
Decoration 패턴을 사용하는 클래스는 주로 namespace ZNsDeco 에 둔
다. 즉, Logic 과 View 구조에서, View 에 해당하는 클래스를 생성
자에서 (주로 참조로) 전달받는 클래스 템플릿이 주요 대상이다.
-- 2010-03-10 22:04:00
////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsDeco*/
namespace ZNsView
{
/*//////////////////////////////////////////////////////////////////////////////////
■ 'Logic-View 구조'(일반적으로는 Document-View 구조라고 얘기를 하는데, 그보다는
'Logic-View 구조'라고 하는 것이 더 적절한 것 같다)에서 View 에 해당하는 클래스는
여기에 놓는다. 여기에 있는 클래스는 접두어 CView 붙여도 좋을 것 같다.
접두어 CView 를 붙이지 않아도, namespace ZNsView 에 있다면 그 클래스는 View 라는
것을 알 수 있는데, 그렇다면 접두어 CView 을 붙일 것인지 말 것인지는, 그때그때 상
황에 맡기기로 하자.
-- 2011-09-11 13:50:00
//////////////////////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsView*/
namespace ZNsViewIFace
{
/*//////////////////////////////////////////////////////////////////////////////////
■ 'Logic-View 구조'에서 View 에 해당하는 어떤 클래스의 interface 를 알려주는 클래스는
여기에 놓는다.
-- 2011-09-11 13:54:00
//////////////////////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsViewIFace*/
namespace ZNsCRTP
{
/*//////////////////////////////////////////////////
■ CRTP : CURIOUSLY RECURRING TEMPLATE PATTERN
CRTP 를 사용하는 클래스 템플릿은 주로 여기에 둔다.
-- 2010-03-12 13:51:00
//////////////////////////////////////////////////*/
}/*
namespace ZNsCRTP*/
namespace ZNsFunc
{
/*///////////////////////////////////////////////////////////////////////////
■ 특수한 목적으로 쓰이는 전역 템플릿 함수는 여기에 놓는다.
■ __FastMoveObj<>(Type1& AR_Type1,Type2& AR_Type2)
차기 표준에서 구현하는 RValue Reference 를 흉내낸 함수다. Move 생성자와
Move 대입연산 중 대입연산만을 흉내내는 것이며, 일반적으로 이 함수 호출후에
AR_Type2 의 크기는 0 이 되거나 줄어들 것이다.
해당 object 에 Move 대입연산이 필요하면 해당 object 를 인수로 갖는
__FastMoveObj() 함수 템플릿을 전문화하면 된다.
■ 어느 함수 func()가 인수로 전달되는 object 의 초기/종료 멤버함수를 요구하는
경우, 그때마다 해당 object class 를 선언할 때, 특정한 이름의 초기/종료 멤버
함수를 선언/정의해야 하는데, 이런 불편함을 약간이라도 감소시키기 위해, func()
에서 해당 object 를 인수로 갖는 전역함수 __Init<>(), __Fini<>() 를 호출하는
것으로 하면 다소 편해질 것이다. 그 후 필요에 따라, __Init, __Fini 템플릿을
전문화하면 된다.
■ -- 2009-08-15 19:57:00
///////////////////////////////////////////////////////////////////////////*/
template<typename Type1, typename Type2>
void __FastMoveObj(Type1& AR_Type1, Type2& AR_Type2)
{
#ifdef _DEBUG_FAST_MOVE_OBJ_
cout<<" ※※ __FastMoveObj Start : Type1="<<typeid(Type1).name()<<", Type2="<<typeid(Type2).name()<<endl;
#endif //_DEBUG_FAST_MOVE_OBJ_
AR_Type1=AR_Type2;
#ifdef _DEBUG_FAST_MOVE_OBJ_
cout<<" ※※ __FastMoveObj Close : Type2="<<typeid(Type1).name()<<", Type2="<<typeid(Type2).name()<<endl;
#endif //_DEBUG_FAST_MOVE_OBJ_
}/*
template<typename Type1, typename Type2>
void __FastMoveObj(Type& AR_Type1, Type& AR_Type2) */
template<typename Type> void __Init(Type& AR_Type)
{
#ifdef _DEBUG
cout<<"void ZNsFunc::__Init<Type>(Type&), Type="<<typeid(Type).name()<<endl;
#endif //_DEBUG
}/*
template<typename Type> void __Init(Type& AR_Type)*/
template<typename Type> void __Fini(Type& AR_Type)
{
#ifdef _DEBUG
cout<<"void ZNsFunc::__Fini<Type>(Type&), Type="<<typeid(Type).name()<<endl;
#endif //_DEBUG
}/*
template<typename Type> void __Fini(Type& AR_Type)*/
/*///////////////////////////////////////////////////////////////////////////
■ CObjAVL<> 등의 클래스에서 object 를 추가하거나 삭제할 때, 아래 중첩 함수를
각각 1 회 씩 최대 2 회 수행하게 되는데,
bool operator> (~)
bool operator==(~)
이를 꼭 1 번만 수행하도록 줄이기 위해 (클래스이지만 실은 함수인)
int ZtCCompare<>::Exec(TTypeArg1 AR_TypeArg1, TTypeArg2 AR_TypeArg2)
를 사용한다.
-- 2012-09-01 20:13:00
AR_Type1==AR_Type2 이면 ZNsEnum::ZECompareResult_Equal ,
AR_Type1>=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이상의 값,
AR_Type1> AR_Type2 이면 ZNsEnum::ZECompareResult_More 이상의 값,
AR_Type1<=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이하의 값,
AR_Type1< AR_Type2 이면 ZNsEnum::ZECompareResult_Less 이하의 값,
을 리턴하거나
AR_Type1>=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이상의 값,
AR_Type1> AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 보다 큰 값,
AR_Type1<=AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 이하의 값,
AR_Type1< AR_Type2 이면 ZNsEnum::ZECompareResult_Equal 보다 작은 값,
을 리턴한다.
-- 2012-09-01 20:20:00
최초에는
template<typename Type1,typename Type2> __CompareObj(Type1, Type2)
라는 함수를 만들어 사용했는데, 템플릿 중첩 정의 시에 상당히 불편했었다.
분명히 문법에 맞게 썼는 것 같은데, 컴파일 에러가 자꾸 나고... 단순히 문
법에 안맞게 써서 그렇다고 한 마디 말로 표현하기에는 어려운 상황이다.
-- 2012-09-02 22:49:00
ZtCCompare<>::Exec(~) 가 template 함수로 선언되어 있는데, 이전에는 template
함수가 아니었다. 이것을 template 함수로 바꾼 이유는 ZtCCompare<> 의 template
인자에 TTypeArg1, TTypeArg2 에 구애받지 않기 위해서다. 따라서 확장성이
약간 상승한다.
-- 2012-10-09 09:14:00
///////////////////////////////////////////////////////////////////////////*/
template< typename TTypeArg1,
typename TTypeArg2,
bool TTypebCompareObj=true
>
class ZtCCompare /////////////////////////
{
public:
enum {ZEUseCompareObj=(ZTypIntE)TTypebCompareObj};
public:
template<typename TTypeArg11, typename TTypeArg22>
static ZTypInt Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
{
#ifdef _DEBUG_CCOMPARE_EXEC
cout<<" ※※ ZtCCompare<TTypeArg1, TTypeArg2, true> is called."<<endl;
#endif //_DEBUG_CCOMPARE_EXEC
return AR_TypeArg1.Compare(AR_TypeArg2);
}/*
template<typename TTypeArg11, typename TTypeArg22>
static ZTypInt Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2) */
public:
};/*
template< typename TTypeArg1,
typename TTypeArg2,
bool TTypebCompareObj=true
>
class ZtCCompare ///////////////////////*/
template<typename TTypeArg1, typename TTypeArg2
>
class ZtCCompare<TTypeArg1, TTypeArg2, false>
{
public:
enum {ZEUseCompareObj=0};
public:
template<typename TTypeArg11, typename TTypeArg22>
static ZTypInt Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
{
return ZNsEnum::ZECompareResult_Equal;
}/*
template<typename TTypeArg11, typename TTypeArg22>
static ZTypInt Exec(TTypeArg1 AR_TypeArg1, TTypeArg2 AR_TypeArg2)*/
public:
};/*
template<typename TTypeArg1, typename TTypeArg2
>
class ZtCCompare<TTypeArg1, TTypeArg2, false> */
template<> class ZtCCompare<ZTypInt, ZTypInt, true>
{
public:
enum {ZEUseCompareObj=1};
public:
static ZTypInt Exec(ZTypInt AI_Int1, ZTypInt AI_Int2)
{
#ifdef _DEBUG_CCOMPARE_EXEC
cout<<" ※※ ZtCCompare<int, int, true> is called."<<endl;
#endif //_DEBUG_CCOMPARE_EXEC
return AI_Int1 - AI_Int2 ;
}/*
static ZTypInt Exec(ZTypInt AI_Int1, ZTypInt AI_Int2)*/
public:
};/*
template<> class ZtCCompare<ZTypInt, ZTypInt, true>*/
/*/////////////////////////////////////////////
■ ZtCMoveObj<> 의 사용례는 CObjAVL.H 에 있다.
-- 2013-08-26 19:18:00
/////////////////////////////////////////////*/
template< typename TTypeArg1,
typename TTypeArg2,
bool TTypebMoveObj=true
>
class ZtCMoveObj ///////////////////////
{
public:
enum {ZEUseMoveObj=(ZTypIntE)TTypebMoveObj};
public:
template<typename TTypeArg11, typename TTypeArg22>
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
{
#ifdef _DEBUG_MOVEOBJ_EXEC
cout<<" ※※ ZtCMoveObj<TTypeArg1, TTypeArg2, true> is called."<<endl;
#endif //_DEBUG_MOVEOBJ_EXEC
return AR_TypeArg1.Compare(AR_TypeArg2);
}/*
template<typename TTypeArg11, typename TTypeArg22>
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2) */
public:
};/*
template< typename TTypeArg1,
typename TTypeArg2,
bool TTypebMoveObj=true
>
class ZtCMoveObj ////////////////////*/
template< typename TTypeArg1, typename TTypeArg2
>
class ZtCMoveObj<TTypeArg1, TTypeArg2, false> ////
{
public:
enum {ZEUseMoveObj=0};
public:
template<typename TTypeArg11, typename TTypeArg22>
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2)
{
AR_TypeArg1 = AR_TypeArg2 ;
}/*
template<typename TTypeArg11, typename TTypeArg22>
static void Exec(TTypeArg11 AR_TypeArg1, TTypeArg22 AR_TypeArg2) */
public:
};/*
template< typename TTypeArg1, typename TTypeArg2
>
class ZtCMoveObj<TTypeArg1, TTypeArg2, false> //*/
}/*
namespace ZNsFunc*/
namespace ZNsTmplChain
{
/*////////////////////////////////////////////////////////////
■ ZtCTmplChain<> 와 유사한 인터페이스를 이용하여, 마치 chain
처럼 호출하는 구조를 갖는 클래스를 여기에 둔다.
-- 2011-08-05 21:16:00
사용례는 CMainChars.H 의
TTypeLength CSearchCursor_T<>::GetLengthByTmplChain(~)
함수를 참고한다.
-- 2011-08-06 23:51:00
////////////////////////////////////////////////////////////*/
template< typename TTypeNow, typename TTypeNext
>
class ZtCTmplChain ////////////////////////////
{
public :
typedef TTypeNow ZCObjNow ;
typedef TTypeNext ZCObjNext;
public :
enum{ZENextObjNo =ZCObjNext::ENextObjNo+1};
enum{ZEBoolNextObj=1 };
private:
TTypeNow mo_ZCObjNow ;
TTypeNext mo_ZCObjNext;
public :
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
ZCObjNext& GetNextObj() {return mo_ZCObjNext;}
/*#####################################################*/
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
const ZCObjNext& GetNextObj() const{return mo_ZCObjNext;}
public:
};/*
template< typename TTypeNow, typename TTypeNext
>
class ZtCTmplChain //////////////////////////*/
template<typename TTypeNow> class ZtCTmplChain<TTypeNow, ZCEmpty>
{
public :
typedef TTypeNow ZCObjNow ;
typedef TTypeNow ZCObjNext;
public :
enum{ZENextObjNo =1};
enum{ZEBoolNextObj=0};
private:
ZCObjNow mo_ZCObjNow;
public :
ZCObjNow& GetNowObj () {return mo_ZCObjNow;}
ZCObjNext& GetNextObj() {return mo_ZCObjNow;}
/*####################################################*/
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow;}
const ZCObjNext& GetNextObj() const{return mo_ZCObjNow;}
public:
};/*
template<typename TTypeNow> class ZtCTmplChain<TTypeNow, ZCEmpty> */
/*//////////////////////////////////////////////////////////////////////////////
■ ZtCTmplTreeChain<> 와 유사한 인터페이스를 이용하여, 마치 chain 의 tree 처럼
호출하는 구조를 갖는 클래스를, ZtCTmplChain<> 와 같은 namespace 에 둔다.
-- 2011-10-04 00:46:00
일종의 2진 트리 형태인데, GetNextObj2() 멤버로 호출하는 노드를 따라서 먼저
처리를 끝내는지, 아니면 GetNextObj() 멤버로 호출하는 노드를 따라서 먼저 처리할
것인지는 경우에 따라 다르다. 일반적으로는 GetNextObj2() 멤버로 호출하는 노드를
따라서 먼저 처리를 하는 것으로 정한다.
-- 2011-10-04 21:01:00
사용례는 CMainChars.H 의
TTypeLength CSearchCursor_T<>::GetLengthByTmplTreeChain(~)
함수를 참고한다.
-- 2011-10-04 00:53:00
//////////////////////////////////////////////////////////////////////////////*/
template< typename TTypeNow ,
typename TTypeNext ,
typename TTypeNext2
>
class ZtCTmplTreeChain /////////
{
public :
enum{ZENextObjNo =TTypeNext ::ENextObjNo +1};
enum{ZENextObjNo2 =TTypeNext2::ENextObjNo2+1};
enum{ZEBoolNextObj =1};
enum{ZEBoolNextObj2=1};
enum{ZEObjChainCnt =TTypeNext::EObjChainCnt+TTypeNext2::EObjChainCnt+2};
public :
typedef TTypeNow ZCObjNow ;
typedef TTypeNext ZCObjNext ;
typedef TTypeNext2 ZCObjNext2;
private:
ZCObjNow mo_ZCObjNow ;
ZCObjNext mo_ZCObjNext ;
ZCObjNext2 mo_ZCObjNext2;
public :
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
ZCObjNext& GetNextObj () {return mo_ZCObjNext ;}
ZCObjNext2& GetNextObj2() {return mo_ZCObjNext2;}
/*########################################################*/
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
const ZCObjNext& GetNextObj () const{return mo_ZCObjNext ;}
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNext2;}
public :
};/*
template< typename TTypeNow ,
typename TTypeNext ,
typename TTypeNext2
>
class ZtCTmplTreeChain ///////*/
template< typename TTypeNow, typename TTypeNext
>
class ZtCTmplTreeChain<TTypeNow, TTypeNext, ZCEmpty>
{
public :
enum{ZENextObjNo =TTypeNext::ENextObjNo +1};
enum{ZENextObjNo2 =0 };
enum{ZEBoolNextObj =1 };
enum{ZEBoolNextObj2=0 };
enum{ZEObjChainCnt =TTypeNext::EObjChainCnt+1};
public :
typedef TTypeNow ZCObjNow ;
typedef TTypeNext ZCObjNext ;
typedef TTypeNext ZCObjNext2; // interface 호환을 위해서만 존재.
private:
ZCObjNow mo_ZCObjNow ;
ZCObjNext mo_ZCObjNext;
public :
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
ZCObjNext& GetNextObj () {return mo_ZCObjNext;}
ZCObjNext2& GetNextObj2() {return mo_ZCObjNext;} // interface 호환을 위해서만 존재.
/*#######################################################*/
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
const ZCObjNext& GetNextObj () const{return mo_ZCObjNext;}
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNext;} // interface 호환을 위해서만 존재.
public :
};/*
template< typename TTypeNow, typename TTypeNext
>
class ZtCTmplTreeChain<TTypeNow, TTypeNext, ZCEmpty> */
template< typename TTypeNow, typename TTypeNext2
>
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, TTypeNext2>
{
public :
enum{ZENextObjNo =0 };
enum{ZENextObjNo2 =TTypeNext2::ENextObjNo2 +1 };
enum{ZEBoolNextObj =0 };
enum{ZEBoolNextObj2=1 };
enum{ZEObjChainCnt =TTypeNext2::EObjChainCnt+1 };
public :
typedef TTypeNow ZCObjNow ;
typedef TTypeNext2 ZCObjNext ; // interface 호환을 위해서만 존재.
typedef TTypeNext2 ZCObjNext2;
private:
ZCObjNow mo_ZCObjNow ;
ZCObjNext2 mo_ZCObjNext2;
public :
ZCObjNow& GetNowObj () {return mo_ZCObjNow ;}
ZCObjNext& GetNextObj () {return mo_ZCObjNext2;} // interface 호환을 위해서만 존재.
ZCObjNext2& GetNextObj2() {return mo_ZCObjNext2;}
/*########################################################*/
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow ;}
const ZCObjNext& GetNextObj () const{return mo_ZCObjNext2;} // interface 호환을 위해서만 존재.
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNext2;}
public :
};/*
template< typename TTypeNow , typename TTypeNext2
>
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, TTypeNext2> */
template< typename TTypeNow ////////////////////
>
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, ZCEmpty>
{
public :
enum{ZENextObjNo =0};
enum{ZENextObjNo2 =0};
enum{ZEBoolNextObj =0};
enum{ZEBoolNextObj2=0};
enum{ZEObjChainCnt =1};
public :
typedef TTypeNow ZCObjNow ;
typedef ZCObjNow ZCObjNext ; // interface 호환을 위해서만 존재.
typedef ZCObjNow ZCObjNext2; // interface 호환을 위해서만 존재.
private:
ZCObjNow mo_ZCObjNow;
public :
ZCObjNow& GetNowObj () {return mo_ZCObjNow;}
ZCObjNext& GetNextObj () {return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
ZCObjNext2& GetNextObj2() {return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
/*######################################################*/
const ZCObjNow& GetNowObj () const{return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
const ZCObjNext& GetNextObj () const{return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
const ZCObjNext2& GetNextObj2() const{return mo_ZCObjNow;} // interface 호환을 위해서만 존재.
public :
};/*
template< typename TTypeNow ////////////////////
>
class ZtCTmplTreeChain<TTypeNow, ZCEmpty, ZCEmpty>
*/
}/*
namespace ZNsTmplChain*/
/*///////////////////////////////////////////////////////////////////
■ 함수가 어떤 조건에서 실행을 중지할 때,
bool 값으로 표시해도 되지만 가독성을 위해서 enum ZERun 을 사용하자.
■ enum ZERun 의 값을 포함해서 에러 상태를 표현하고 싶을 때에는,
enum ZERunEx 를 사용하자.
-- 2011-09-27 05:37:00
///////////////////////////////////////////////////////////////////*/
namespace ZNsEnum
{
enum ZERun
{
ZERun_NO, // 실행 중지
ZERun_OK // 실행 계속
};/*
enum ZERun*/
enum ZERunEx
{
ERunEx_NO, // 실행 중지
ERunEx_OK, // 실행 계속
ERunEx_Err // 실행 에러
};/*
enum ZERun*/
enum ZEAct
{
ZEAct_NO, // (함수 등이) 어떤 조건에 맞지 않아서 아무 짓도 하지 않았다.
ZEAct_OK // (함수 등이) 어떤 조건에 맞아서 지정된 처리를 하였다.
};/*
enum ZEAct*/
enum ZEActEx
{
ZEActEx_NO, // (함수 등이) 어떤 조건에 맞지 않아서 아무 짓도 하지 않았다.
ZEActEx_OK, // (함수 등이) 어떤 조건에 맞아서 지정된 처리를 하였다.
ZEActEx_Err // (함수 등이) 수행 중에 에러가 발생하였다.
};/*
enum ZEAct*/
enum ZEThrowFinally
{
ZEThrowFinally_NO,
ZEThrowFinally_OK
};/*
enum ZEThrowFinally*/
/*////////////////////////////////////////////////
■ 타 언어의 throw ~ catch ~ finally 를 흉내낼 때
EThrowFinally 예외를 던진다.
////////////////////////////////////////////////*/
}/*
namespace ZNsEnum*/
namespace ZNsInterface
{
/*////////////////////////////////////////////////////////////////////////////////////
■ class ZIDelgtMSG 는 C# 의 delegate 삼아서 만든 클래스.
어느 object 가 하나 이상의 다른 object 에게 어떤 메시지를 전달하고 싶을 때, 메시지를
전송하는 object 는, 수신하는 object 의 기반클래스 ZIDelgtMSG 의 참조나 포인터를 멤버
로 가지고 있다가, ZIDelgtMSG::SendMSG() 나 ZIDelgtMSG::RecvMSG() 을 호출하면 된다.
■ COM 개념을 상당부분 포함하고 있다. 간단하게 COM 대용으로 써도 될 듯 하다.
-- 2009-03-08 02:26:00
■ class ZIDelgtMSG 를 상속하여 추가 멤버함수를 가진 인터페이스를 구현하는 클래스일 경우
에는 namespace ZNsInterface 에 두지 말고 namespace ZNsIDelgt 에 두자.
-- 2009-03-08 19:17:00
■ A, B, C 클래스가 서로의 존재를 알아야 한다고 할 때도 사용할 수 있겠다. 그런데 이런 경
우는 굳이 ZIDelgtMSG 를 사용하지 말고, 단순 가상 함수 클래스를 사용해도 된다. 그게 더
간단할 것이다. 그래도 ZIDelgtMSG 를 사용한다면, interface 의 일관성을 얻을 수 있다는 게
장점이 될 수 있다.
-- 2010-03-13 22:28:00
////////////////////////////////////////////////////////////////////////////////////*/
class ZIDelgtMSG
{
public:
enum ZEIMsg{ZEIMsg_NO=0, ZEIMsg_OK=1};
public:
virtual ~ZIDelgtMSG(){}
virtual ZTypLLong GetTypeID() const
{
return 0;
}/*
virtual ZTypLLong GetTypeID() const*/
virtual const char* GetTypeName() const
{
return 0;
}/*
virtual const char* GetTypeID() const*/
virtual ZTypLLong GetIMSGPtrOfID(ZTypLLong AI_TypeID, ZIDelgtMSG*& APR_ZIDelgtMSG)
{
APR_ZIDelgtMSG=0; return ZEIMsg_OK;
}/*
virtual ZTypLLong GetIMSGPtrOfID(ZTypLLong AI_TypeID, ZIDelgtMSG*R APR_ZIDelgtMSG)*/
virtual ZTypIntPtr SendMSG(ZIDelgtMSG& ArZIDelgtMSG, ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypIntI AI_MsgLen, void* AP_Void=0, ...)
{
return ZEIMsg_OK;
}/*
virtual ZTypIntPtr SendMSG(ZIDelgtMSG& ArZIDelgtMSG, ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypIntI AI_MsgLen,void* AP_Void=0, ...)*/
virtual ZTypIntPtr RecvMSG(ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypLength AI_MsgLen, void* AP_Void=0, ...)
{
return ZEIMsg_OK;
}/*
virtual ZTypIntPtr RecvMSG(ZTypIntI AI_MsgNo, const char* ApcMsgData, ZTypLength AI_MsgLen, void* AP_Void=0, ...)*/
public:
};/*
class ZIDelgtMSG*/
}/*
namespace ZNsInterface*/
namespace ZNsIDelgt
{
// class ZIDelgtMSG 를 상속하여 추가 멤버함수를 가진
// 인터페이스를 구현하는 클래스일 경우에는 여기에 둔다.
}/*
namespace ZNsIDelgt*/
class ZCAllocator
{
public:
static void* operator new (size_t AL_AllocSize ){return ::malloc(AL_AllocSize);}
static void* operator new[](size_t AL_AllocSize ){return ::malloc(AL_AllocSize);}
static void* operator new (size_t AL_AllocSize, void* AP_AllocBegin){return AP_AllocBegin ;}
static void* operator new[](size_t AL_AllocSize, void* AP_AllocBegin){return AP_AllocBegin ;}
static void operator delete (void* AP_Void){if(AP_Void!=0) ::free(AP_Void);}
static void operator delete[](void* AP_Void){if(AP_Void!=0) ::free(AP_Void);}
public:
};/*
class ZCAllocator*/
/*/////////////////////////////////////////////////////////////////
■ class ZCAllocator 는 정적 멤버를 사용하지만
class ZtCAllocClass<> 는 비정적 멤버를 사용한다.
■ 기본메모리 할당자로 ZtCAllocClass<> 을 사용하는 클래스가 나중에
다른 할당 알고리즘을 사용하고 싶을 때는 ZtCAllocClass<> 템플릿을
해당 Type 으로 전문화시켜주면 된다.
/////////////////////////////////////////////////////////////////*/
template<typename TType>
class ZtCAllocClass : public ZCAllocator
{
public:
TType* NewMem (size_t AL_AllocSize){return (TType*)::malloc(AL_AllocSize) ;}
TType* NewArrMem(size_t AL_AllocSize){return (TType*)::malloc(AL_AllocSize*sizeof(TType));}
public:
void DeleteMem(void* AP_Void){if(AP_Void!=0) ::free(AP_Void);}
public:
};/*
template<typename TType> class ZtCAllocClass*/
class ZCAllocClass : public ZCAllocator
{
public:
void* NewMem (size_t AL_AllocSize){return ::malloc(AL_AllocSize) ;}
void DeleteMem(void* AP_Void ){if(AP_Void!=0) ::free(AP_Void);}
public:
};/*
class ZCAllocClass : public ZCAllocator*/
/*//////////////////////////////////////////////////////////////
■ 가끔 템플릿으로 클래스 설계를 하다보면 템플릿의 parameter 가
포인터나 참조일 경우, 무엇의 포인터나 참조형인지 알고 싶을 때
가 있다. 이런 경우에 ZtCTypeData<> 를 사용한다.
cf)
cout<<typeid(std::ZtCTypeData<ZTypIntI >::TypeData).name()<<endl;
cout<<typeid(std::ZtCTypeData<ZTypIntI*>::TypeData).name()<<endl;
cout<<typeid(std::ZtCTypeData<ZTypIntI&>::TypeData).name()<<endl;
-- 2010-01-15 00:11:00
■ ZtCTypeData<>::GetObjRef(~) 는 아래처럼 주로 포인터 자료형을
(null 이 아닌 경우) 항상 참조형으로 다루고 싶을 때 사용한다.
템플릿 Parameter 가 포인터형인데, 무엇의 포인터 형인지 알아
내어, 참조형으로 만들어 다른 함수의 인수로 사용하거나, 해당
멤버의 호출을 포인터 참조 표기 -> 말고 참조 표기(.)로 하면 편
할 것이다.
typedef std::CStringBase_T<char> CStringData ;
typedef CStringData* CStringDataPtr;
CStringData VO_CStringData("My");
CStringDataPtr VP_CStringData=&VO_CStringData;
(*VP_CStringData)("Data");
cout<<ZtCTypeData<CStringDataPtr>::GetObjRef(VP_CStringData)<<endl;
■ --
//////////////////////////////////////////////////////////////*/
template<typename TType> class ZtCTypeData
{ public: typedef TType TypeData;
static TType& GetObjRef(TType& AR_Type){return AR_Type ;}};
template<typename TType> class ZtCTypeData<TType*>
{ public: typedef TType TypeData;
static TType& GetObjRef(TType* AP_Type){return *AP_Type;}};
template<typename TType> class ZtCTypeData<TType&>
{ public: typedef TType TypeData;
static TType& GetObjRef(TType& AR_Type){return AR_Type ;}};
template< > class ZtCTypeData<void* >
{ public: typedef void* TypeData;
static void* GetObjRef(void* AP_Void){return AP_Void ;}};
/*////////////////////////////////////////////////////////////////////////////////
■ 문자열 클래스에서 새로 메모리를 증가시켜야 할 때, 필요한 메모리보다 약간 더 할
당하는 것이 좋을 경우가 있는데, 이 경우에 필요한 메모리보다 어느 정도 만큼의 메
모리를 할당한 것인지를 지정한다.
////////////////////////////////////////////////////////////////////////////////*/
template<typename TTypeCh> class ZtCAllocMemSize
{
public:
template<typename TTypeSize>
TTypeSize GetNewAllocSize(TTypeSize AL_NowAllocSize, TTypeSize AL_AllAllocSize)
{
/* AL_AllAllocSize : 해당 문자열 object 가 할당받은 문자 총갯수.
AL_NowAllocSize : AL_AllAllocSize 에서 현재 유효한 문자 갯수. */
return AL_NowAllocSize<=AL_AllAllocSize ? AL_NowAllocSize : AL_NowAllocSize*2 ;
}/*
template<typenanme TTypeSize>
TTypeSize GetNewAllocSize(TTypeSize AL_NowAllocSize, TTypeSize AL_AllAllocSize) */
public:
};/*
template<typename TTypeCh> class ZtCAllocMemSize */
/*//////////////////////////////////////////////////////////////
■ 아래 템플릿은 양방향 리스트에서 n 번째 원소에 접근할 때, 앞에
서부터 접근하는 것이 빠를지, 뒤에서부터 접근하는 것이 빠를지
판단할 때 사용한다.
//////////////////////////////////////////////////////////////*/
template<typename TTypSize> class ZtCShortCut
{
private:
static inline TTypSize GetAbs(TTypSize AI_Param) // 인수의 절대값을 얻는다.
{
return (AI_Param<0 ? -AI_Param : AI_Param);
}/*
static inline TTypSize GetAbs(TTypSize AI_Param)*/
/*private:*/
public :
static ZTypIntI GetAbsMinOrder(TTypSize AI_One, TTypSize AI_Two, TTypSize AI_Three)
{
// 세 개의 인수 중에서 절대값이 최소가 되는 수는
// 몇 번째 인지 그 순서를 반환한다.
// 맨 앞의 인수가 절대값이 최소면 1 을 반환한다.
// 두 번째 인수의 절대값이 최소면 2 를 반환한다.
// 세 번째 인수의 절대값이 최소면 3 을 반환한다.
// 이 함수는 양방향 원형 연결리스트에서 n 번째 링크를 찾는데 쓰인다.
return ( GetAbs(AI_One)<=GetAbs(AI_Two ) /******/ ?
(GetAbs(AI_One)<=GetAbs(AI_Three) ? 1 : 3) :
(GetAbs(AI_Two)<=GetAbs(AI_Three) ? 2 : 3)
/****/ );
};/*
static ZTypIntI GetAbsMinOrder(TTypSize AI_One,TTypSize AI_Two, TTypSize AI_Three)*/
public:
};/*
template<typename TTypSize> class ZtCShortCut*/
#ifdef _WIN
/*/////////////////////////////////////////////////
inline ZTypIntI GetLastError(){return ::GetLastError();}
/////////////////////////////////////////////////*/
using ::GetLastError;
template<typename TString>
static bool GetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0)
{
LPVOID VP_MsgBuff; DWORD ViErrNo=(AI_ErrNo==0 ? ::GetLastError() : AI_ErrNo);
const DWORD CI_RetCode = ::FormatMessage( ///////////////
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS ,
NULL ,
ViErrNo ,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)&VP_MsgBuff,0,NULL
/*//////////*/ ); ///////////////////////////////////////
if(CI_RetCode==0) return false;
(ARR_BuffCStr=
((LPCTSTR)VP_MsgBuff))(", ErrNo=")(ViErrNo);
::LocalFree(VP_MsgBuff); return true;
}/*
template<typename TString>
static bool GetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0) */
// defined(_WIN)
#elif defined(__unix__)
inline ZTypIntI GetLastError()
{
return errno ; // ::error 로 하면 안된다.
}/*
inline ZTypIntI GetLastError()*/
template<typename TString>
static bool GetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0)
{
if(AI_ErrNo==0)
ARR_BuffCStr = ::strerror(errno );
else ARR_BuffCStr = ::strerror(AI_ErrNo);
return true; // for compatibility with window
}/*
template<typename TString>
static bool GetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0) */
//#elif defined(__unix__)
#else
inline ZTypIntI GetLastError(){return errno ;}
template<typename TString>
static bool GetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0)
{
if(AI_ErrNo==0)
ARR_BuffCStr = ::strerror(errno );
else
ARR_BuffCStr = ::strerror(AI_ErrNo);
//else
return true; // for compatibility with window
}/*
template<typename TString>
static bool GetLastErrMSG(TString& ARR_BuffCStr, ZTypIntI AI_ErrNo=0) */
#endif
// 절대값을 가져온다.
template<typename TLong> TLong ABS(TLong AL_Value)
{
if(AL_Value<0) return -AL_Value; return AL_Value;
}/*
template<typename TLong> TLong ABS(TLong AL_Value) */
template<typename TypeInt>
TypeInt AToInt(const char* ApcChar, ZTypIntI AI_Length)
{
if(AI_Length<1) return 0;
while(AI_Length>0 && ApcChar[AI_Length-1]==' ')
--AI_Length; // 뒤에 있는 공백을 제외.
//while
if(AI_Length<1) return 0;
const char* VPC_Char =ApcChar+AI_Length-1;
TypeInt VL_Temp;
TypeInt VL_Result =(*VPC_Char--)-'0';
TypeInt VL_Multiple=1;
while(--AI_Length>0)
{
if((VL_Temp=*VPC_Char--)<'0' || VL_Temp>'9' ) return 0;
VL_Result += (VL_Multiple*=10)*(VL_Temp-'0') ; ////////
}/*
while(--AI_Length>0)*/
return VL_Result;
}/*
template<typename TypeInt>
TypeInt AToInt(const char* ApcChar, ZTypIntI AI_Length) */
#ifdef _WIN
inline ZTypLLong ATOLL(const char* ApcChar)
{
if(ApcChar==0) return 0; return ::_atoi64(ApcChar);
}/*
inline ZTypLLong ATOLL(const char* ApcChar)*/
#else // !defined(_WIN)
inline ZTypLLong ATOLL(const char* ApcChar)
{
if(ApcChar==0) return 0; return ::atoll(ApcChar);
}/*
inline ZTypLLong ATOLL(const char* ApcChar)*/
#endif // !defined(_WIN)
inline ZTypLLong ATOLL(const char* ApcChar, ZTypIntI AI_Length)
{
return AToInt<ZTypLLong>(ApcChar, AI_Length);
}/*
inline ZTypLLong ATOL(const char* ApcChar, ZTypIntI AI_Length)*/
inline ZTypLong ATOL(const char* ApcChar)
{
if(ApcChar==0) return 0; return atol(ApcChar);
}/*
inline ZTypLong ATOL(const char* ApcChar)*/
inline ZTypLong ATOL(const char* ApcChar, ZTypIntI AI_Length)
{
return AToInt<ZTypLong>(ApcChar, AI_Length);
}/*
inline ZTypLong ATOL(const char* ApcChar, ZTypIntI AI_Length)*/
inline ZTypIntI ATOI(const char* ApcChar)
{
if(ApcChar==0) return 0; return atoi(ApcChar);
}/*
inline ZTypIntI ATOI(const char* ApcChar)*/
inline ZTypIntI ATOI(const char* ApcChar, ZTypIntI AI_Length)
{
return AToInt<ZTypIntI>(ApcChar, AI_Length);
}/*
inline ZTypIntI ATOI(const char* ApcChar, ZTypIntI AI_Length)*/
inline double ATOD(const char* ApcChar)
{
return ApcChar==0 ? 0 : ::atof(ApcChar) ;
}/*
inline double ATOD(const char* ApcChar)*/
template<typename TTypeCh>
inline ZTypLength GetLength(const TTypeCh* ApcChar)
{
if(ApcChar==0) return 0;
ZTypLength VL_Length=0 ;
while(*(ApcChar+VL_Length)!=_T('\0'))
++VL_Length;
/////////////////////////////////////
return VL_Length;
}/*
template<typename TTypeCh>
inline ZTypLength GetLength(const TTypeCh* ApcChar) */
template<typename TTypeSize, typename TTypeCh>
inline TTypeSize GetLengthType(const TTypeCh* ApcChar)
{
if(ApcChar==0) return 0;
TTypeSize VL_Length=0 ;
while(*(ApcChar+VL_Length)!=_T('\0'))
++VL_Length;
/////////////////////////////////////
return VL_Length;
}/*
template<typename TTypeSize, typename TTypeCh>
inline TTypeSize GetLengthType(const TTypeCh* ApcChar) */
/*//////////////////////////////////////////////////////////////////////////////////////
■ CopyChars() 함수는 최대 AL_DestSize 만큼 복사하는데, ZNsWin.H 의 CRegistry 클래스에서
Windows 의 Strsafe.h 에 정의된 StringCchCopy() 을 대신하려고 만들었다. mingw 에서는
헤더 파일 Strsafe.h 이 없는 경우가 있는 것이다. 원래 StringCchCopy() 선언은 이렇다.
HRESULT StringCchCopy(
__out LPTSTR pszDest,
__in size_t cchDest,
__in LPCTSTR pszSrc
);
This function can return one of the following values. It is strongly recommended
that you use the SUCCEEDED and FAILED macros to test the return value of this function.
Return code
S_OK : Source data was present, fully copied without truncation, and the resultant
destination buffer is null-terminated.
STRSAFE_E_INVALID_PARAMETER : The value in cchDest is either 0 or larger than STRSAFE_MAX_CCH.
STRSAFE_E_INSUFFICIENT_BUFFER : The copy operation failed due to insufficient buffer
space. The destination buffer contains a truncated, null-terminated version of the
intended result. In situations where truncation is acceptable, this may not necessarily
be seen as a failure condition.
-- 2012-08-15 07:40:00
//////////////////////////////////////////////////////////////////////////////////////*/
template<typename TTypeCh, typename TTypeSize>
TTypeSize CopyChars(TTypeCh* ApcDest, TTypeSize AL_DestSize, const TTypeCh* ApcSource)
{
/* ApcSource must be null-terminated. AL_DestSize
must be equal to or more than strlen(ApcSource)+1.
Null 문자를 포함하여 ApcDest 에 복사된 길이를 리턴한다. */
if(ApcSource==0) return 0;
TTypeSize VL_SourceSize=0 ;
TTypeCh* VPC_Dest =ApcDest ;
const TTypeCh* VPC_Source =ApcSource;
for(; VL_SourceSize<AL_DestSize; ++VL_SourceSize)
{
if(*ApcSource==0)
{
if(VL_SourceSize<AL_DestSize+1)
{
*VPC_Dest=0; return VL_SourceSize+1;
}/*
if(VL_SourceSize<AL_DestSize+1)*/
return VL_SourceSize;
}/*
if(*ApcSource==0)*/
*VPC_Dest = *VPC_Source;
}/*
for(; VL_SourceSize<AL_DestSize; ++VL_SourceSize)*/
}/*
template<typename TTypeCh, typename TTypeSize>
TTypeSize CopyChars(TTypeCh* ApcDest, TTypeSize AL_DestSize, const TTypeCh* ApcSource) */
template<typename TType> class ZtCInit
{
public:
void operator()(TType& AR_TypeArg){}
public:
void OnInit(TType& AR_TypeArg){}
void OnFini(TType& AR_TypeArg){}
public:
};/*
template<typename TType> class ZtCInit*/
class ZCInit
{
public:
template<typename TType> void operator()(TType& AR_TypeArg){}
template<typename TType> void OnInit (TType& AR_TypeArg){}
template<typename TType> void OnFini (TType& AR_TypeArg){}
void OnInit(){}
void OnFini(){}
public:
};/*
class ZCInit*/
class CExceptBase
{
public: void* operator()(){return 0;}
};/*
class CExceptBase*/
// 예외 기반 클래스를 template 로 하면 여러 기법을 사용할 수 있다.
template< typename TType, typename TypeArg=const TType&
>
class CExceptBase_T /*/////////////////////////////////*/
{
protected:
TType mo_Type;
public :
CExceptBase_T(){}
CExceptBase_T(TypeArg TypeArgObj):mo_Type(TypeArgObj){}
TType& operator()(){return mo_Type;}
public :
};/*
template< typename TType, typename TypeArg=const TType&
>
class CExceptBase_T ///////////////////////////////////*/
/*/////////////////////////////////////////////////////////////////////////////////
■ 이 클래스를 private 상속하는 클래스에서 복사생성자와 대입연산자의 사용을 막는다.
■ template class 나 class member template 을 사용할 때, 인수가 class object 이고
이 인수가 반드시 참조형으로 전달되어야하고, 복사 생성되어 전달될 수 없을때, 이를
보장하기 위해 해당 class 를 아래 class 로부터 상속할 필요가 있다.
이를 모르고 있다가, CAsyncServ_H 에 정의된 CAsyncServ_T<> 클래스를 사용할 때, 이
클래스가 작업쓰레드 풀 인수로 복사 생성되어 전달되는 것을 나중에 알고 깜짝 놀랬다.
-- 2010-12-20 23:51:00
/////////////////////////////////////////////////////////////////////////////////*/
class CNonCopyable
{
private:
CNonCopyable(const CNonCopyable& rhs){}
CNonCopyable& operator=(const CNonCopyable& rhs){return *this;}
public :
CNonCopyable(){}
public :
};/*
class CNonCopyable*/
/*///////////////////////////////////////////////////////////////////////////
■ 리스트나 트리 구조에서 쓰는 링크의 힙-자유 기억 공간-을 구현하는 class 는
class ZCFreeAllocBase 를 상속한다. 이 자유 기억 공간 클래스의 object 는 힙
에 할당한다.
///////////////////////////////////////////////////////////////////////////*/
class ZCFreeAllocBase
{
public:
virtual ~ZCFreeAllocBase(){}
virtual long GetHeapSize() const{return 0;}
virtual long GetMemSize () const{return 0;}
const char* GetTypeName() const
{
return typeid(*this).name();
}/*
const char* GetTypeName() const*/
virtual void DeleteAllInHeap(){}
public:
};/*
class ZCFreeAllocBase*/
// 자유 기억 공간을 총괄하는 단방향 연결 리스트
class ZCHeapAllocList
{
public:
class ZCLink
{
public:
friend class ZCHeapAllocList;
public:
ZCLink(ZCFreeAllocBase& ArCFreeAllocBase):mr_AllocBase(ArCFreeAllocBase), mp_NextLink(0)
{
}/*
ZCLink(ZCFreeAllocBase& ArCFreeAllocBase)*/
ZCLink* GetNextLink()
{
return mp_NextLink;
}/*
ZCLink* GetNextLink()*/
ZCLink* GetNextLink(long AL_Distance)
{
ZCLink* VP_NowLink=this;
while(--AL_Distance>=0)
VP_NowLink=VP_NowLink->mp_NextLink;
return VP_NowLink;
}/*
ZCLink* GetNextLink(long AL_Distance)*/
ZCFreeAllocBase& GetData()
{
return mr_AllocBase;
}/*
ZCFreeAllocBase& GetData()*/
/*public :*/
private:
ZCFreeAllocBase& mr_AllocBase;
ZCLink* mp_NextLink ;
private:
};/*
class ZCLink*/
/*public :*/
private:
ZTypIntL ml_Size ;
ZCLink* mp_HeadLink ;
ZCLink* mp_TailLink ;
private:
void AddLink(ZCLink* AP_NewLink)
{
if(ml_Size++ == 0)
{
mp_HeadLink= mp_TailLink=AP_NewLink ;
mp_TailLink->mp_NextLink=mp_HeadLink;
}
else
{
mp_TailLink->mp_NextLink=AP_NewLink ;
AP_NewLink ->mp_NextLink=mp_HeadLink;
mp_TailLink=mp_TailLink->mp_NextLink;
}/*
else*/
}/*
void AddLink(ZCLink* AP_NewLink)*/
/*private:*/
public :
ZCHeapAllocList()
{
ml_Size =0;
mp_HeadLink =0;
mp_TailLink =0;
}/*
ZCHeapAllocList()*/
template<typename TypeFreeAlloc> TypeFreeAlloc& AddFreeAlloc()
{
// TypeFreeAlloc 은 ZCFreeAllocBase 의 파생클래스여야 한다.
TypeFreeAlloc* VP_TypeFreeAlloc=new TypeFreeAlloc;
ZCLink* VP_NewLink=new ZCLink(*VP_TypeFreeAlloc);
AddLink(VP_NewLink); return *VP_TypeFreeAlloc;
}/*
template<typename TypeFreeAlloc> TypeFreeAlloc& AddFreeAlloc() */
void AddFreeAllocBase(ZCFreeAllocBase& ArCFreeAllocBase)
{
AddLink( new ZCLink(ArCFreeAllocBase) );
}/*
void AddFreeAllocBase(ZCFreeAllocBase& ArCFreeAllocBase)*/
ZCFreeAllocBase& GetData(long AL_Index)
{
return mp_HeadLink->GetNextLink(AL_Index-1)->mr_AllocBase;
}/*
ZCFreeAllocBase& GetData(long AL_Index)*/
ZCLink* GetHeadLink()
{
return mp_HeadLink;
}/*
ZCLink* GetHeadLink()*/
template<typename DeriveType> DeriveType& GetDataType(long AL_Index)
{
return static_cast<DeriveType&>( mp_HeadLink->GetNextLink(AL_Index-1)->mr_AllocBase );
}/*
template<typename DeriveType> DeriveType& GetDataType(long AL_Index) */
void FreeAll()
{
ZCLink* VP_Link=mp_HeadLink;
for(long i=1; i<=ml_Size; ++i)
{
VP_Link->mr_AllocBase.DeleteAllInHeap();
VP_Link=VP_Link->mp_NextLink;
}/*
for(long i=1; i<=ml_Size; ++i)*/
}/*
void FreeAll()*/
void DeleteAll()
{
ZCLink* VP_CutLink=0;
for(long i=1; i<=ml_Size; ++i)
{
VP_CutLink =mp_HeadLink;
mp_HeadLink=mp_HeadLink->mp_NextLink;
delete VP_CutLink;
}/*
for(long i=1; i<=ml_Size; ++i)*/
ml_Size=0;
}/*
void DeleteAll()*/
void ClearAll()
{
ZCLink* VP_CutLink=0;
for(long i=1; i<=ml_Size; ++i)
{
VP_CutLink =mp_HeadLink ;
mp_HeadLink=mp_HeadLink->mp_NextLink;
VP_CutLink->
mr_AllocBase.DeleteAllInHeap() ;
delete VP_CutLink;
}/*
for(long i=1; i<=ml_Size; ++i)*/
ml_Size=0;
}/*
void ClearAll()*/
ZTypIntL GetSize() const
{
return ml_Size;
}/*
ZTypIntL GetSize() const*/
public:
};/*
class ZCHeapAllocList*/
static ZCHeapAllocList& GetCHeapAllocList()
{
static ZCHeapAllocList SO_CHeapAllocList; return SO_CHeapAllocList;
}/*
static ZCHeapAllocList& GetCHeapAllocList()*/
/*//////////////////////////////////////////////////////////////////
■ 템플릿 인자를 정의할 때 참조로 하지 않은 경우에 object 의 크기가
크면 포인터로 넘겨야 하는데, 이러면 어느 object 의 포인터인지 알
수 있지만 그 object 에 속한 enum 형이나 typedef 선언 및 기타 자료
형은 알 수 없다. 그래서 object 의 포인터를 포장하는 클래스 템플릿
ZtCObjectPtr<> 을 설계한다.
■ typedef ZtCStringBase<char > CStringBase;
typedef ZtCObjectPtr <CStringBase> CObjectPtr ;
라는 선언이 있으면 CStringBase::TTypeChar 에 접근할 때에는
CObjectPtr::TypeData::TTypeChar 로 하면 된다.
■ 포인터 자료형에 대하여 ZtCObjectPtr<> 대신 더 간단하게
ZtCTypeData<> 를 사용해도 된다. 이 편이 오히려 낳을 것 같다.
-- 2010-01-24 22:25:00
//////////////////////////////////////////////////////////////////*/
template<typename TType> class ZtCObjectPtr
{
public :
typedef TType TypeData;
protected:
TType& mr_TypeData;
public :
ZtCObjectPtr(TType& ArCData):mr_TypeData(ArCData){}
TType* operator->(){return &mr_TypeData;}
TType& operator* (){return mr_TypeData;}
operator TType& (){return mr_TypeData;}
public :
};/*
template<typename TType> class ZtCObjectPtr */
/*/////////////////////////////////////////////////////////
■ object 를 heap 에 생성하고, 참조 카운트를 이용하여 관리.
-- 2014-07-20 04:49:00
/////////////////////////////////////////////////////////*/
template< typename TType, typename TAllocClass=ZCAllocClass
>
class ZtCObjectNew : public TAllocClass ////////////////////
{
public :
typedef TType TypeData ;
typedef TAllocClass ZCAllocator;
private:
struct StTypeRefCnt
{
TType MO_TypeData;
ZTypInt MI_RefCount;
StTypeRefCnt(){MI_RefCount=0;}
};/*
struct StTypeRefCnt*/
private:
StTypeRefCnt* mp_StTypeRefCnt;
public :
ZtCObjectNew()
{
mp_StTypeRefCnt = (StTypeRefCnt*)
this->ZCAllocator::NewMem( sizeof(StTypeRefCnt) );
mp_StTypeRefCnt->MI_RefCount = 1 ;
new(&mp_StTypeRefCnt->MO_TypeData) TypeData;
}/*
ZtCObjectNew()*/
ZtCObjectNew(const TypeData& AR_TypeData)
{
mp_StTypeRefCnt = (StTypeRefCnt*)
this->ZCAllocator::NewMem( sizeof(StTypeRefCnt) );
mp_StTypeRefCnt->MI_RefCount = 1 ;
new(&mp_StTypeRefCnt->MO_TypeData) TypeData(AR_TypeData);
}/*
ZtCObjectNew(const TypeData& AR_TypeData)*/
template<typename TTypeArg1, typename TTypeArg2>
ZtCObjectNew(TTypeArg1& ArTTypeArg1, TTypeArg2& ArTTypeArg2)
{
mp_StTypeRefCnt = (StTypeRefCnt*)
this->ZCAllocator::NewMem(sizeof(StTypeRefCnt));
mp_StTypeRefCnt->MI_RefCount = 1 ;
new(&mp_StTypeRefCnt->MO_TypeData)
TypeData(ArTTypeArg1, ArTTypeArg2);
}/*
template<typename TTypeArg1, typename TTypeArg2>
ZtCObjectNew(TTypeArg1& ArTTypeArg1, TTypeArg2& ArTTypeArg2))*/
ZtCObjectNew(const ZtCObjectNew& rhs)
{
mp_StTypeRefCnt=rhs.mp_StTypeRefCnt; ++mp_StTypeRefCnt->MI_RefCount;
}/*
ZtCObjectNew(const ZtCObjectNew& rhs)*/
~ZtCObjectNew()
{
if(--mp_StTypeRefCnt->MI_RefCount<=0) this->ZCAllocator::DeleteMem(mp_StTypeRefCnt);
}/*
~ZtCObjectNew()*/
ZtCObjectNew& operator=(const ZtCObjectNew& rhs)
{
if(this==&rhs || mp_StTypeRefCnt==rhs.mp_StTypeRefCnt) return *this;
#if(0)
mp_StTypeRefCnt->MO_TypeData = rhs.mp_StTypeRefCnt->MO_TypeData; return *this;
#else
if(--mp_StTypeRefCnt->MI_RefCount<=0) this->ZCAllocator::DeleteMem(mp_StTypeRefCnt);
mp_StTypeRefCnt = rhs.mp_StTypeRefCnt; ++mp_StTypeRefCnt->MI_RefCount; return *this;
#endif
}/*
ZtCObjectNew& operator=(const ZtCObjectNew& rhs)*/
ZtCObjectNew& operator=(const TypeData& AR_TypeData)
{
if(&mp_StTypeRefCnt->MO_TypeData==&AR_TypeData) return *this;
mp_StTypeRefCnt->MO_TypeData = AR_TypeData; return *this;
}/*
ZtCObjectNew& operator=(const TypeData& AR_TypeData)*/
TypeData& operator* (){return mp_StTypeRefCnt->MO_TypeData;}
TypeData* operator->(){return &mp_StTypeRefCnt->MO_TypeData;}
operator TypeData& (){return mp_StTypeRefCnt->MO_TypeData;}
ZTypInt GetRefCnt() const{return mp_StTypeRefCnt->MI_RefCount;}
TypeData* GetObjPtr() const{return &mp_StTypeRefCnt->MO_TypeData;}
public :
};/*
template< typename TType, typename TAllocClass=ZCAllocClass
>
class ZtCObjectNew : public TAllocClass //////////////////*/
#ifdef _DEBUG
/*/////////////////////////////////////////////////////////////////////
■ 멀티쓰레드 환경에서는 반드시 _REENTRANT 이 정의되어 있어야 한다. 이
것을 체크하기 위해 쓰레드를 만드는 클래스가 있다면 생성자에서 아래
함수를 호출해서 _REENTRANT 가 정의되어 있는지 확인한다.
-- 2009-12-23 10:38:00
/////////////////////////////////////////////////////////////////////*/
inline void _DEBUG_REENTRANT_Check()
{
if(_REENTRANT_BOOL_<1)
{
std::fstream fileout("DEBUG.txt", std::ios::out | std::ios::app);
fileout<<"◆◆ Error! : _REENTRANT is Not Defined In Multi-Thread"<<std::endl;
fileout.close();
::exit(1);
}/*
if(_REENTRANT_BOOL_<1)*/
}/*
inline void _DEBUG_REENTRANT_Check()*/
#define _DEBUG_REENTRANT_CHECK_ _DEBUG_REENTRANT_Check();
#else // !defined(_DEBUG)
#define _DEBUG_REENTRANT_CHECK_
#endif // !defined(_DEBUG)
#if defined(_REENTRANT)
class ZCExceptSmallLock : public CExceptBase
{
private:
long ml_ErrCode;
string mo_ErrMSG ;
public :
ZCExceptSmallLock(long AL_ErrCode, const char* AP_ErrMSG)
{
ml_ErrCode=AL_ErrCode; //////////////
if(AP_ErrMSG!=0) mo_ErrMSG=AP_ErrMSG;
}/*
ZCExceptSmallLock(long AL_ErrCode, const char* AP_ErrMSG)*/
long GetErrCode() const{return ml_ErrCode;}
const string& GetErrMSG() const{return mo_ErrMSG;}
public:
};/*
class ZCExceptSmallLock*/
#endif //defined(_REENTRANT)
#if defined(_REENTRANT) && defined(_WIN)
/*//////////////////////////////////////////////////////
■ 아래 클래스는 여러 자료구조에서 내부적으로 정적변수나
정적 object 를 동기화하기 위해 사용한다.
윈도우에서는 크리티컬 섹션을 쓰는 것이 좋으나
BOOL TryEnterCriticalSection(LPCRITICAL_SECTION)
함수가 제대로 지원되지 않고 있다.
//////////////////////////////////////////////////////*/
class ZCMutexSmallLock;
class ZCMutexSmallInit
{
private:
HANDLE mh_Mutex;
public :
void Lock() throw(ZCExceptSmallLock&)
{
long VL_ErrCode=0;
if((VL_ErrCode = ::WaitForSingleObject(mh_Mutex, INFINITE))==WAIT_ABANDONED)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::Lock()");
}/*
if((VL_ErrCode = ::WaitForSingleObject(mh_Mutex, INFINITE))==WAIT_ABANDONED)*/
}/*
void Lock() throw(ZCExceptSmallLock&)*/
void UnLock()
{
::ReleaseMutex(mh_Mutex);
}/*
void UnLock()*/
ZCMutexSmallInit()
{
/* MUTEX 를 신호 상태로 만들고 이 함수를 호출한 쓰레드가 MUTEX 를 소유하지 않게
한다. 신호 상태라 함은 다른 쓰레드가 진입할 수 있는 상태를 말한다. */
mh_Mutex = ::CreateMutex(NULL, FALSE, NULL);
}/*
ZCMutexSmallInit()*/
~ZCMutexSmallInit()
{
::CloseHandle(mh_Mutex);
}/*
~ZCMutexSmallInit()*/
public:
};/*
class ZCMutexSmallInit*/
class ZCMutexSmallLock
{
private:
ZCMutexSmallInit& mr_ZCMutexInit;
public :
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit):mr_ZCMutexInit(ArZCMutexInit)
{
mr_ZCMutexInit.Lock();
}/*
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit)*/
~ZCMutexSmallLock()
{
mr_ZCMutexInit.UnLock();
}/*
~ZCMutexSmallLock()*/
public:
};/*
class ZCMutexSmallLock*/
#elif defined(_REENTRANT) && defined(__unix__)
// 유닉스(특히 리눅스) 상에서 _REENTRANT 이 정의되어 있으면
// -lpthread 옵션을 잊지 말 것.
class ZCMutexSmallLock;
class ZCMutexSmallInit
{
private:
::pthread_mutex_t mo_Mutex;
public :
void Lock() throw(ZCExceptSmallLock&)
{
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::Lock()");
}/*
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)*/
}/*
void Lock() throw(ZCExceptSmallLock&)*/
void UnLock() throw(ZCExceptSmallLock&)
{
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::UnLock()");
}/*
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)*/
}/*
void UnLock() throw(ZCExceptSmallLock&)*/
ZCMutexSmallInit() throw(ZCExceptSmallLock&)
{
::pthread_mutexattr_t VO_MutexAttr;
::pthread_mutexattr_init(&VO_MutexAttr);
::pthread_mutexattr_settype(&VO_MutexAttr, PTHREAD_MUTEX_RECURSIVE);
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::ZCMutexSmallInit()");
}/*
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)*/
}/*
ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)
{
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::~ZCMutexSmallInit()");
}/*
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)*/
}/*
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
public:
};/*
class ZCMutexSmallInit*/
class ZCMutexSmallLock
{
private:
ZCMutexSmallInit& mr_ZCMutexInit;
public :
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit):mr_ZCMutexInit(ArZCMutexInit)
{
mr_ZCMutexInit.Lock();
}/*
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit)*/
~ZCMutexSmallLock()
{
mr_ZCMutexInit.UnLock();
}/*
~ZCMutexSmallLock()*/
public:
};/*
class ZCMutexSmallLock*/
// defined(_REENTRANT) && defined(__unix__)
#elif defined(_REENTRANT)
// _REENTRANT 이 정의되어 있으면 -lpthread 옵션을 잊지 말 것.
class ZCMutexSmallLock;
class ZCMutexSmallInit
{
private:
::pthread_mutex_t mo_Mutex;
public :
void Lock() throw(ZCExceptSmallLock&)
{
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::Lock()");
}/*
if((VL_ErrCode=::pthread_mutex_lock(&mo_Mutex))!=0)*/
}/*
void Lock() throw(ZCExceptSmallLock&)*/
void UnLock() throw(ZCExceptSmallLock&)
{
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::UnLock()");
}/*
if((VL_ErrCode=::pthread_mutex_unlock(&mo_Mutex))!=0)*/
}/*
void UnLock() throw(ZCExceptSmallLock&)*/
ZCMutexSmallInit() throw(ZCExceptSmallLock&)
{
::pthread_mutexattr_t VO_MutexAttr;
::pthread_mutexattr_init(&VO_MutexAttr);
::pthread_mutexattr_settype(&VO_MutexAttr, PTHREAD_MUTEX_RECURSIVE);
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::ZCMutexSmallInit()");
}/*
if((VL_ErrCode=::pthread_mutex_init(&mo_Mutex, &VO_MutexAttr))!=0)*/
}/*
ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)
{
long VL_ErrCode=0;
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)
{
throw ZCExceptSmallLock(VL_ErrCode, "ZCMutexSmallInit::~ZCMutexSmallInit()");
}/*
if((VL_ErrCode=::pthread_mutex_destroy(&mo_Mutex))!=0)*/
}/*
~ZCMutexSmallInit() throw(ZCExceptSmallLock&)*/
public:
};/*
class ZCMutexSmallInit*/
class ZCMutexSmallLock
{
private:
ZCMutexSmallInit& mr_ZCMutexInit;
public :
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit):mr_ZCMutexInit(ArZCMutexInit)
{
mr_ZCMutexInit.Lock();
}/*
ZCMutexSmallLock(ZCMutexSmallInit& ArZCMutexInit)*/
~ZCMutexSmallLock()
{
mr_ZCMutexInit.UnLock();
}/*
~ZCMutexSmallLock()*/
public :
};/*
class ZCMutexSmallLock*/
#endif //defined(_REENTRANT)
#if defined(_DEBUG) && defined(_REENTRANT)
class ZCSyncLog
{
private :
typedef ZCMutexSmallInit CSync;
protected:
static CSync& GetCSync()
{
static CSync SO_CSyncLog; return SO_CSyncLog;
}/*
static CSync& GetCSync()*/
public :
ZCSyncLog (){GetCSync().Lock ();}
~ZCSyncLog(){GetCSync().UnLock();}
public :
};/*
class ZCSyncLog*/
#endif // defined(_DEBUG) && defined(_REENTRANT)
#ifdef _DEBUG
static inline void WriteError(const char* ApcErrorStr)
{
std::fstream fileout(
"DEBUG.txt", std::ios::out | std::ios::app);
fileout<<ApcErrorStr<<std::endl;
fileout.close();
::exit(1);
}/*
static inline void WriteError(const char* ApcErrorStr)*/
/*///////////////////////////////////////////////////////////////////
■ 이 object 를 멤버로 가진 object 는 container 외부에 만들어질 수 없다.
container 의 링크나 노드를 설계할 때 그 링크나 노드가(DEBUG 모드에서)
Stack 에 만들어지는지 혹은 container 외부에서 new 로 만들어지는지를
체크할 때 유용하다. container 의 링크는 container 내부에서만 new,
delete 되어야 한다.
///////////////////////////////////////////////////////////////////*/
class ZCCheckAlloc
{
public :
class ZCAllowAlloc; friend class ZCAllowAlloc;
private:
static bool& GetAllowAllocBool()
{
static bool SB_AllowAlloc=false; return SB_AllowAlloc;
}/*
static bool& GetAllowAllocBool()*/
/*private:*/
public :
ZCCheckAlloc()
{
if(GetAllowAllocBool()==false)
{
cout<<endl<<"Warning! Unallowed Object Memory Allocation!"<<endl<<endl;
}/*
if(GetAllowAllocBool()==false)*/
}/*
ZCCheckAlloc()*/
static bool IsAllowAlloc()
{
return GetAllowAllocBool();
}/*
static bool IsAllowAlloc()*/
/*public:*/
public:
class ZCAllowAlloc
{
private:
bool mb_AllowAlready ;
/*///////////////////////////////////////////////////////
■ 위 멤버변수를 설계하면 ZCAllowAlloc object 멤버함수가
중첩호출될 경우, 가장 처음에 호출하는 함수가
ZCCheckAlloc::GetAllowAllocBool()=false;
이 부분을 수행하게 된다. 결국 중첩호출 도중에
ZCCheckAlloc::GetAllowAllocBool() 은 항상 true 가 된다.
■ --
///////////////////////////////////////////////////////*/
/*private:*/
public :
ZCAllowAlloc()
{
mb_AllowAlready=ZCCheckAlloc::GetAllowAllocBool();
ZCCheckAlloc::GetAllowAllocBool()=true; //////////
}/*
ZCAllowAlloc()*/
~ZCAllowAlloc()
{
if(mb_AllowAlready==false) ZCCheckAlloc::GetAllowAllocBool()=false;
}/*
ZCAllowAlloc()*/
public:
};/*
class ZCAllowAlloc()*/
public:
};/*
class ZCCheckAlloc*/
static ZTypIntL SI_Count_DEBUG=0;
#endif //_DEBUG
namespace ZNsConst
{
#if defined(_WIN)
#define __DIR_DELIMITERS__ "\\"
#define __DIR_DELIMITER__ '\\'
ZTypCPCCh CPC_DirDelimiter="\\";
ZTypCChar CC_DirDelimiter ='\\';
#else //!(defined(_WIN)
#define __DIR_DELIMITERS__ "/"
#define __DIR_DELIMITER__ '/'
ZTypCPCCh CPC_DirDelimiter="/";
ZTypCChar CC_DirDelimiter ='/';
#endif //!(defined(_WIN)
}/*
namespace ZNsConst*/
}/*
namespace ZNsMain*/
namespace ZNsCPP
{
using ZNsMain::IterEasyID;
/* 이 이름공간에는 ZNsMain 에 있는 라이브러리 보다 좀더 thread-safe
하거나 좀더 최적화된, 아니면 좀 더 gerneric 한 자료구조가 온다.
*/
namespace ZNsInterface
{
}/*
namespace ZNsInterface*/
namespace ZNsIFace
{
using namespace ZNsInterface;
}/*
namespace ZNsIFace*/
namespace ZNsType
{
}/*
namespace ZNsType*/
namespace ZNsEnum
{
}/*
namespace ZNsEnum*/
namespace ZNsConst
{
}/*
namespace ZNsConst*/
}/*
namespace ZNsCPP */
/* 함수 안에서 함수를 정의할 필요가 있을 때, struct 를 이용하여 함수를 정의하는 매크로. -- 2015-09-06 05:20:00 */
#define _FUNC_IN_FUNC_START_(ZstClassName) struct ZstClassName{static void Exec
#define _FUNC_IN_FUNC_CLOSE_(ZstClassName) };
#define _FUNC_IN_FUNC_RETURN_START_(ZstClassName, ZTypeReturn) struct ZstClassName{static ZTypeReturn Exec
#define _FUNC_IN_FUNC_RETURN_CLOSE_(ZstClassName, ZTypeReturn) };
#define _FFS_(ZstClassName) _FUNC_IN_FUNC_START_(ZstClassName)
#define _FFC_(ZstClassName) _FUNC_IN_FUNC_CLOSE_(ZstClassName)
#define _FFE_(ZstClassName) }; // E 문자는 END 의 뜻.
#define _FFRS_(ZstClassName, ZTypeReturn) _FUNC_IN_FUNC_RETURN_START_(ZstClassName, ZTypeReturn)
#define _FFRC_(ZstClassName, ZTypeReturn) _FUNC_IN_FUNC_RETURN_CLOSE_(ZstClassName, ZTypeReturn)
#define _FFRE_(ZstClassName) };
#define _FFF_(ZstClassName) ZstClassName::Exec
/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
■ _FUNC_IN_FUNC_START_ 관련 매크로 사용예.
#include<iostream>
using namespace ZNsMain;
int main()
{
_FUNC_IN_FUNC_START_(My)
(IntI ArgiShowCnt)
{
for(int i=0; i<ArgiShowCnt; ++i) cout<<"# Show My() In Func."<<endl;
}
_FUNC_IN_FUNC_CLOSE_(My)
_FUNC_IN_FUNC_RETURN_START_(My2, Int)
(IntI ArgiShowCnt)
{
for(int i=0; i<ArgiShowCnt; ++i) cout<<"# Show My() In Func."<<endl; return ArgiShowCnt;
}
_FUNC_IN_FUNC_RETURN_CLOSE_(My2, int)
_FFS_(My3)
(IntI ArgiShowCnt)
{
for(int i=0; i<ArgiShowCnt; ++i) cout<<"# Show My() In Func."<<endl; return ArgiShowCnt;
}
_FFC_(My3)
My ::Exec(3);
My2::Exec(3);
My3::Exec(3);
return 0;
}
-- 2015-09-06 17:21:00
CNetEx.H 의 HandleEvent 도 참고. -- 2015-09-06 17:43:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
■ 4.1 자동적으로 정의되는 심볼들
여러분은 여러분이 갖고 있는 버전의 gcc 가 -v 옵션을 붙임으로써
어떠한 심볼을 자동적으로 정의하는지 알아낼 수 있다.
예를 들어 본인의 것은 다음과 같다.
$ echo 'main(){printf("hello world\n");}' | gcc -E -v -
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
gcc version 2.7.2
/usr/lib/gcc-lib/i486-box-linux/2.7.2/cpp -lang-c -v -undef
-D__GNUC__=2 -D__GNUC_MINOR__=7 -D__ELF__ -Dunix -Di386 -Dlinux
-D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386
-D__linux -Asystem(unix) -Asystem(posix) -Acpu(i386)
-Amachine(i386) -D__i486__ -
--
현재 위 명령으로는 더 이상 매크로를 알 수 없는데, 아래 명령
echo . | gcc -dM -E -
혹은
gcc -dM -E - < /dev/null
을 이용하면 된다.
ex) gcc -dM -E - < /dev/null | grep 'linux'
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
ex) echo . | gcc -dM -E - | grep 'unix'
#define __unix 1
#define __unix__ 1
#define unix 1
이것은 ymir 님의 답변이었다. ☞ http://kldp.org/node/121720
-- 2011-03-03 13:21:00
■ 각 OS 별 매크로
리눅스 : #define __linux__ 1
HP : #define __hpux__ 1
sun : #define __sun__ 1
IRIX : #define __mips__ 1
TRUE64 : #define __alpha__ 1
FreeBSD: #define __FreeBSD_cc_version 800001
#define __VERSION__ "4.2.1 20070719 [FreeBSD]"
#define __FreeBSD__ 8
AIX : #define _AIX 1
#define _AIX32 1
#define _AIX41 1
#define _AIX43 1
#define _AIX51 1
#define _AIX52 1
#define _AIX53 1
-- 2011-03-12 16:17:00
■ 만약 여러분의 코드가 리눅스에만 관계되는 코드라면, 다음과 같이 해주는 것이 좋다.
#ifdef __linux__
// ... funky stuff ...
#endif // __linux__
__linux__라는 이름을 사용하라. linux가 아니다.
후자가 정의되어 있기는 하지만 POSIX 규격에는 맞지 않기 때문이다.
■ 각 OS 별 Shared Library PATH 환경 변수 (2012-04-08 19:25:00)
※ http://cafe335.daum.net/_c21_/bbs_search_read?grpid=TzUN&fldid=DUnV&contentval=0000szzzzzzzzzzzzzzzzzzzzzzzzz&nenc=&fenc=&q=gulim.ttf&nil_profile=cafetop&nil_menu=sch_updw
AIX LIBPATH, LD_LIBRARY_PATH
OS/2 LIBPATH
Windows NT/95 PATH
Solaris/Linux LD_LIBRARY_PATH
HP/UX SHLIB_PATH, LD_LIBRARY_PATH (64 bit only)
ex) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/userJNI/lib
※ HP-UX 에서 Shared Library 의 확장자는 sl 이다.
□ SUN일 경우 LD_LIBRARY_PATH 를 HP-UX 일 경우 SHLIB_PATH 를, AIX 일 경우 LIBPATH 를 사용합니다.
□ 참고 : HP에서 LD_LIBRARY_PATH 는 64비트 환경에서만 작동함. 확장자 명도 sl 임
□ chatr 명령을 사용하면 SHLIB_PATH가 사용 중인 프로그램에 대해 "사용 불가능" 상태인지 여부를 판별할 수 있습니다.
다음 예는 /opt/mqm/samp/bin/amqsput 프로그램에 사용되는 chatr 명령입니다.
chatr /opt/mqm/samp/bin/amqsput
프로그램이 SHLIB_PATH를 사용하는지 확인하려면 다음 명령을 실행하십시오.
chatr +s enable /opt/mqm/samp/bin/amqsput
SHLIB_PATH 가 환경에 정의되어 있으며 /usr/lib 디렉토리를 포함하는지 확인하십시오(echo $SHLIB_PATH).
경로를 정의하려면 다음을 실행하십시오.
export SHLIB_PATH=$SHLIB_PATH:/usr/lib
□ 다음은 어플리케이션에 대해 SHLIB_PATH 또는 chatr +s 가 조사되어야 함을 지시하는 어플리케이션 오류입니다.
◆ IBM WebSphere MQ 프로그램 runmqsc
runmqsc D11LHP.QM
5724-B41 (C) Copyright IBM Corp. 1994, 2002. ALL RIGHTS RESERVED.
Starting MQSC for queue manager D11LHP.QM.
/usr/lib/dld.sl: Can't find path for shared library: libstream.2
/usr/lib/dld.sl: No such file or directory
AMQ9508: Program cannot connect to the queue manager.
No MQSC commands read.
No commands have a syntax error.
All valid MQSC commands were processed.
◆ IBM WebSphere MQ 샘플 어플리케이션이 권한 부여 오류를 표시함(이유 코드 2217)
amqsput QL_D11LHP_B02KLNX.U1.I D11LHP.QM
Sample AMQSPUT0 start
target queue is QL_D11LHP_B02KLNX.U1.I
MQOPEN ended with reason code 2217
unable to open queue for output
Sample AMQSPUT0 end
◆ --
□ --
■ 'new operator' 와 'operator new' Programming
(2007/04/03 16:20)
http://blog.naver.com/cppis/60036113050
bugmail에게 More Effective C++을 빌려 보던 중 일반적으로 많이 쓰던 new와 delete에 대해서 소홀하게 넘어갔던 부분을
보고 정리를 하게 되었습니다. 저와 마찬가지로 많은 사람들이 'new operator' 와 'operator new'를 혼동하시는 것 같아서
간단히 정리해봤습니다.
'new operator'는 C++ 에서 제공하는 연산으로 두 가지 동작을 수행합니다.
-- 먼저, 요청한 타입 크기의 메모리를 할당하고, 다음으로, 타입 인스턴스의 생성자를 호출하여 초기화를 수행합니다.
C++ 컴파일러는 'new operator'를 위의 내용처럼 코드로 만들어냅니다. 'operator new'란 바로 요청한 타입 크기의 메모리
를 할당하는 동작을 수행하는 Operator입니다.
따라서 위의 내용을 다시 요약하면, 'new operator'는 'operator new'로 메모리를 할당하고, object 의 생성자를 호출하는
동작을 한다." 라고 할 수 있습니다.
'operator new'는 Overload 될 수 있기 때문에 사용자가 자신만의 'operator new'를 정의할 수 있습니다. 또, 항상 void*
를 리턴하고, 첫번째 인자로 size_t를 받습니다. 'new operator'의 문법은 다음과 같습니다.
[::] new [placement] new-type-name [new-initializer]
[::] new [placement] ( type-name ) [new-initializer]
- placement
new 를 overload 할 때 추가로 인자를 전달하는 방법을 제공합니다. 예를 들어, 표준 C++ 라이브러리의 default new는 메
모리가 바닥나면 exception 을 throw합니다. Overload 된 new 는 대신 NULL을 리턴하는데, Overload 된 new 는 다음과 같
이 정의되어 있습니다.
struct nothrow_t {};
extern const nothrow_t nothrow;
void *operator new throw() (size_t, const nothrow_t& );
그리고 다음과 같이 호출될 수 있습니다
foo *fp = new (nothrow) foo;
if( !fp ) {
// Out of memory를 처리합니다.
}
- type-name
할당할 타입을 명시합니다. type-name은 built-in 이거나 user-defined 타입일 수 있습니다.
- initializer
초기화할 object를 위한 값을 제공합니다. initializer 는 object 배열을 할당하기 위해서는 사용될 수 없습니다. 'new
operator'는 default 생성자를 가지고 있는 object 의 배열만을 생성할 수 있습니다.
new 중에서 'Placement-new'는 메모리를 전혀 할당하지 않고, object 의 생성자를 호출하기 위해서만 사용됩니다. 'Placement-new'
는 일반적으로 다음과 같이 정의되어 있습니다.
inline void *operator new( size_t, void* p )
{
return p;
}
Automatic Variable을 제외한다면 'Placement-new'는 object 의 생성자를 호출할 수 있는 유일한 방법입니다. new 와 쌍(
Pair)인 delete도 이와 비슷합니다.
'delete operator'는 object 의 소멸자를 호출하고,
'operator delete'를 호출하여 메모리를 해제하는 동작을 수행합니다.
reference
- More Effective C++
- MSDN
■ Placement-New Requires Heap-Allocated Buffers
The placement-new operator constructs an object on a pre-allocated buffer. The pre-allocated buffer has to be allocated
on the heap.
char *pbuff = new char[1024]; // heap allocation using plain new
Person *p = new (pbuff) Person; // placement new uses a pre-allocated buffer
You may be tempted to use a buffer allocated on the stack to avoid the need of explicitly freeing it:
char pbuff [1024]; //bad idea: stack allocation instead of heap
Person *p = new ( pbuff ) Person; //undefined behavior
However, the pre-allocated buffer must comply with certain alignment constraints required by C++. Memory allocated
on the heap is guaranteed to comply with these requirements. Stack memory, on the other hand, may not be properly aligned,
and hence using it for that purpose yields undefined behavior
-- heap 에서는 정렬 제한이 정확히 지켜지지만
-- stack 에서는 정렬 제한이 지켜지지 않을 수 있다.
-- (아마도 위에서 버퍼 pbuff[1024] 의 주소 pbuff 이 heap 기준에 어긋나는,
-- 정렬되지 않은 주소일 수도 있다는 뜻인 듯 하다.) 2008-10-26
http://kldp.org/node/76375
http://www.devx.com/tips/Tip/12756
■ 어떤 클래스에 멤버변수를 추가하게 되면 생성자에서 초기화해야 하는지 한 번 더 생각하자. 생성자에서 초기화를 빠트려
서 애먹은 적이 있었다.
■ 클래스가 어떤 주기적인 상태를 가지는 경우, 한 주기가 끝날 때마다 내부 버퍼를 정확하게 초기화하자. 각 포탈이나 신
문사의 검색페이지에서 검색결과를 가져와 해석할 때, 각 검색페이지의 각 리스트 항목의 데이타 추출이 끝나면, 다음 리
스트 항목을 추출할 때 관련 버퍼를 초기화해 주어야 했는데 여기에 실수가 있어서, 추출시에 이전 정보가 자꾸 들러 붙었
다. 처음에는 이게 오류인 줄 알았고 들러붙은 것이 이전 정보인지도 몰랐다. 알고보니 다음 항목 추출 전에 관련 버퍼를
초기화 안한 실수였다.
■ 가상함수를 상속클래스에서 재정의할 때는 기본값 인수 갯수도 동일해야 한다.
virtual CIOCP ::SendPacket(HANDLE SocketID,const char* ApcData=0,int AI_Length=0,CSendBuffList* AP_CSendBuffList=0) // 1) 번코드
virtual CIOCPEx::SendPacket(HANDLE SocketID,const char* ApcData=0,int AI_Length=0) // 2) 번코드
1) 번 코드는 기반클래스의 가상 함수이고
2) 번 코드는 상속클래스의 재정의함수다. 그리고 아래의 코드에서
CIOCPEx VO_CIOCPEx;
CIOCP* VP_CIOCP=&VO_CIOCPEx;
VO_CIOCPEx->SendPacket((HANDLE)100,"my",2); // 어느 함수가 호출될까.
위 코드는 CIOCP::SendPacket() 을 호출하게 된다.
-- 2009-01-03 13:09:00
■ 여러 오브젝트 파일에서 사용되는 문자열 상수는
const char* CPC_MySQL_Host="localhost" 이 아니고
const char* const CPC_MySQL_Host="localhost" 로 선언해야 한다.
■ 템플릿으로 상속을 구현하면, 템플릿 parameter 에 따라 기반 클래스를 마음대로 바꿀 수가 있다. 이 기능이 상당히 편하
긴 한데 조심할 점이 한 가지 있다.
template<typename TTypeBase>
class CMy : public TTypeBase
{
public:
void Init();
void Fini();
};
위 클래스 템플릿을 상속해서 CMy2 를 만든다음
clear() 멤버를 추가한다고 하자. 그러면
class CMy2 : public CMy<CBaseClass>
{
public:
void clear();
};
위외 같은 형태가 될텐데, 이때 clear() 멤버를 정의하면서 기반클래스인 CMy<CBaseClass> 의 멤버변수와 함수를 어떻게
사용하겠는지 한 번쯤 생각을 하게 된다. 그런데 CMy<CBaseClass> 의 기반클래스인 CBaseClass 에 대해서는 자칫 생각을
못하게 된다. clear() 함수가 어떤 자원을 해제하는 함수라면 CBaseClass 의 관련 자원을 해제하는 처리를 빠트릴 수 있는
것이다. 따라서 템플릿 기반의 상속 구현에서 기반클래스의 관련 멤버에 대해서도 어떤 처리가 필요한지 한 번 더 따져봐
야 한다.
상속클래스를 템플릿 parameter 로 받는 클래스 템플릿을 상속하는 경우에도 마찬가지로 주의해야 한다.
CHttp.H 파일에서 std::ZNsCGI::ZNsThpe::ZtCTypeLoadDataQuery_T<> template 에서도 clear() 멤버를 Override 하고 있는데,
위와 상황은 약간 다르지만 유사한 헛점이 생겼던 코드이다. clear() 멤버는 자원을 해제하는 함수인데 이 함수를 재정의
하지 않는 상태에서
ZtCTypeLoadDataQuery_T<> ::clear() 을 호출하니
std::CLoadDataBlockOne_T<>::clear() 만을 호출하고
또다른 기반 클래스인 TTypeBase 의 자원을 해제하지 못하고 있었다. 그래서 부랴부랴 TTypeBase 인자에 해당하는 클래스
에 clear() 멤버를 추가하고 ZtCTypeLoadDataQuery_T<>::clear() 을 재정의한 함수 정의에, 코드
std::CLoadDataBlockOne_T<>::clear()
this->TTypeBase ::clear()
을 추가시켰다. 그제야 결과가 정상이었다. 이전에는 이상하게 짝수번 실행시에 결과가 엉뚱하게 나왔었다. clear() 시에
기반클래스 TTypeBase 인
std::ZNsIFace::CDeriveLoadDataQuery_T<TString>
클래스에서 멤버 me_ESearch 을 ESearch_Name 으로 초기하지 못하고 있었던 것이다. 그러니까 처음 실행시에는
me_ESearch==ESearch_Name 이니까 정상이고 2 번째 실행시에
me_ESearch!=ESearch_Name 이니까 엉뚱한 결과가 나오고, 이때 우연치 않게도
me_ESearch==ESearch_Name 으로 다시 초기화되고, 3 번째 실행시에는
me_ESearch==ESearch_Name 이니까 정상이고...
게다가 갑자기 breakpoint 가 먹질 않고... 휴 진땀뺏다. -- 2009-01-05 10:02:00
■ CHttp.H 에 가상 기초클래스가 필요한 상황에 어떻게 템플릿으로 구현하는지 그 예가 있다. 여러 개의 상속클래스에서 공
통이 되는 멤버를, 상속클래스에서 선언및 정의하는 방법을 사용하고 있다.
이 방법을 "가상 상속의 템플릿 구현(TIVI : Template Implementation Of Virtual Inheritance)" 이라고 하자.
CHttp.H 에서 사용한 이런 기법이 다른 경우에도 적용될 수 있다. 프로그램이 커지면 여러 가지 클래스를 정의하게 되고,
어떠 클래스를 정의하기 전에, 다른 클래스 정의를 요구하고 또 다른 클래스 object 를 요구할 수 있다. 다른 클래스 정의
를 요구하는 경우는 그 클래스 앞에 요구하는 클래스를 미리 정의하면 간단한데, 다른 클래스 object (참조, 포인터) 를
외부에서 요구하는 경우는 처리가 복잡해진다. 그때마다 전역 인스턴스를 만들자니 뭔가 찝찝하다. 예를 들어 A, B, C,D,E
클래스가 있는데
B 는 외부의 A 의 object 참조를 요구하고
C 는 외부의 B 의 object 참조를 요구하고
D 는 외부의 C 의 object 참조를 요구하고
E 는 외부의 D 의 object 참조를 요구하는 상황이라고 하자. 그러면
A 를 정의하고 A 전역 object 를 만들고
B 를 정의하고 B 전역 object 를 만들고
C 를 정의하고 C 전역 object 를 만들고
D 를 정의하고 D 전역 object 를 만드는 과정을 반복해야 한다.
이렇게 하면 전역object 가 어지럽게 널려 있게 된다. 이런 상황에서도 "가상 상속의 템플릿 구현" 을 사용할 수 있겠다.
-- 2009-01-18 17:48:00
음, "가상 상속의 템플릿 구현" 을 좀 더 곰곰히 생각해 보면, 스트립트 언어에서는 이런 경우를 '어떻게 처리할까' 라는
궁금증이 생긴다. 근데 스트립트 언어에서는 데이타형에서 자유롭기 때문에 이런 상황을 풀어 내기가 훨씬 쉬워 보인다.
데이타형에서 자유롭기 때문에 얻어지는 이 장점이 과연 좋은 것일까. 버그가 더 발생하기 쉽지 않을까.
-- 2009-01-19 01:21:00
위에서 예로 든 object A,B,C,D,E 의 관계를 이렇게 풀 수도 있겠다.
A 를 정의하고
A 의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 B 를 만들고
B 의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 C 를 만들고
C 의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 D 를 만든다.
이 개념을 가상함수로 풀면,
A 를 정의하고
A 의 기초클래스의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 B 를 만들고
B 의 기초클래스의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 C 를 만들고
C 의 기초클래스의 참조(나 포인터)를 생성자에서 인수로 받는 클래스 D 를 만든다.
-- 2009-01-19 01:26:00
이런 상황이 더 복잡해진다면 적절한 작업쓰레드를 모델링해서 해결하는 것도 좋을 것 같다.
(WTM 은 Working Thread Model)
A 의 역할을 하는 IOCP 형 작업쓰레드 모델 A-WTM 을 만들고
B 의 역할을 하는 IOCP 형 작업쓰레드 모델 B-WTM 을 만들고
C 의 역할을 하는 IOCP 형 작업쓰레드 모델 C-WTM 을 만들고 ...
만약 A,B 나 C,D 를 하나의 단위로 묶을 수 있다면,
A,B 의 역할을 하는 IOCP 형 작업쓰레드 모델 AB-WTM 을 만들고
C,D 의 역할을 하는 IOCP 형 작업쓰레드 모델 CD-WTM 을 만들고...
--
이 문제는 COM(Component Object Model) 방식으로 해결할 수도 있겠다.
cf) std::ZNsIFace::ZIDelgtMSG
-- 2009-03-09 20:18:00
"가상 상속의 템플릿 구현"은 꼭 가상 함수의 다중 상속이 필요한 상황 외에도 클래스 A, B, C, D 가 서로의 인터페이스에
접근하는 복잡한 상황에서도 사용할 수 있겠다. 클래스 A, B, C, D 를 상속클래스 템플릿인자를 받도록 선언하고, 클래스
A, B, C, D 를 상속하는 클래스 E 를 만든 다음에, 이 E 를 통해 A, B, C, D 각 클래스에 접근할 수 있다. 즉 상속클래스
가 기반 클래스들의 중간 다리역할을 하고 있는 것이다.
cf) MainHead_VirtualDeriveTmpl.cpp
"가상 상속의 템플릿 구현" 은 CURIOUSLY RECURRING TEMPLATE PATTERN 과 일맥상통한다.
class template A 가 다수 개의 class B1,B2,B3 의 존재를 알아야 하고, 또 class B1, B2, B3 는 A 의 존재를 알아야 하는
순환 인식 구조에서도 적용하면 아주 좋을 것 같다. 또한 class B1, B2, B3 가 서로의 존재를 알아야 할 때도 유용하다.
class B1, B2, B3 의 멤버함수를 호출할 때, A 의 상속클래스 A2 를 넘기면, A2 에 B1, B2, B3 에 접근하는 interface 가
있기 때문에, B1 에서 B2 나 B3 의 interface 에 접근할 수가 있는 것이다.
ex)
1) 먼저 상속 클래스를 템플릿 인자로 받는 class template A 를 정의한다.
2) A 의 상속 클래스에 B1, B2, B3 클래스의 인터페이스가 있다는 가정하에
B1, B2, B3 클래스의 인터페이스를 사용하는 멤버함수를 A 에 추가한다.
3) A 의 상속 클래스에서, B1, B2, B3 클래스 object 에 접근할 수 있는,
인터페이스를 정의한다.
template<typename TParent>
class A
{
public:
void UseB1(){static_cast<TParent*>(this)->GetObjB1().CallFunc();}
void UseB2(){static_cast<TParent*>(this)->GetObjB2().CallFunc();}
void UseB3(){static_cast<TParent*>(this)->GetObjB3().CallFunc();}
void UseExB1(TParent& ArCParent){static_cast<TParent*>(this)->GetObjB1().CallFunc(ArCParent);}
void UseExB2(TParent& ArCParent){static_cast<TParent*>(this)->GetObjB2().CallFunc(ArCParent);}
void UseExB3(TParent& ArCParent){static_cast<TParent*>(this)->GetObjB3().CallFunc(ArCParent);}
};
class A2 : public A<A2>
{
public:
class B1{public:void CallFunc() {cout<<"Call B1::CallFunc()"<<endl;}
void CallFunc(A2& ArA2){cout<<"Call B1::CallFunc(A2)"<<endl;}};
class B2{public:void CallFunc() {cout<<"Call B2::CallFunc()"<<endl;}
void CallFunc(A2& ArA2){cout<<"Call B2::CallFunc(A2)"<<endl;}};
class B3{public:void CallFunc() {cout<<"Call B3::CallFunc()"<<endl;}
void CallFunc(A2& ArA2){cout<<"Call B3::CallFunc(A2)"<<endl;}};
private:
B1 b1;
B2 b2;
B3 b3;
public:
B1 GetObjB1(){return b1;}
B2 GetObjB2(){return b2;}
B3 GetObjB3(){return b3;}
void UseExB1(){A<A2>::UseExB1(*this);}
void UseExB2(){A<A2>::UseExB2(*this);}
void UseExB3(){A<A2>::UseExB3(*this);}
};
A2 myA2;
myA2.UseB1();
myA2.UseB2();
myA2.UseB3();
myA2.UseExB1();
myA2.UseExB2();
myA2.UseExB3();
-- 2010-03-12 11:56:00
그런데 가상함수 클래스를 이용하면 더 간단할 수 있다. 예를 들어 클래스 A,B,C 에 접근할 수 있는 인터페이스를 제공하
는 가상함수 클래스 IA, IB, IC 를 만들고, 클래스 A, B, C 는 각각 IA, IB, IC 클래스를 상속한다. 그 다음 IA, IB, IC
의 포인터를 관리하는 singleton object SngtA, SngtB, SngtC 를 정의하고, 클래스 A, B, C 는 생성후, 바로(혹은 빠른 시
간 안에), SngtA, SngtB, SngtC 가 관리하는 가상함수 클래스의 포인터를 자신의 포인터로 설정해 준다.
이러면 A, B, C 는 singleton object SngtA, SngtB, SngtC 를 통해 서로의 interface 를 호출할 수 있다. 가상함 수의 사
용이 부담되지 않는다면 이 방법이 더 편할 수 있다.
-- 2010-03-13 22:43:00
■ 작업쓰레드 pool P1 에서 class A, B 를 사용하는데, A,B 는 P1 보다 먼저 선언해야 하지만, B 는 내부적으로 P1 을 사용
하고 있어서 P1 이후에 선언해야 한다고 생각해보자. 그러면 선언/정의 순서가 A => P1 => B 가 된다. 그런데 P1 은 B 라
는 자료형을 알아야 하는데, 이것은 P1 의 작업쓰레드의 수행 함수를 템플릿으로 만들어서 인자를 받게 하고, P1 의 Instance
를 B 에서 만들면서 템플릿 인자로 B 를 넘겨주면 된다.
클래스 테플릿 CThreadEx_T<> 와 파일 CProxySockHttpXml.H 을 참고한다.
-- 2009-08-09 20:23:00
■ 기초클래스의 생성자에서 파생클래스의 참조(나 포인터)를 인수로 받는 경우가 있는데, 이때 기초 클래스의 생성자에서는
파생클래스의 멤버가 초기화되기 전이므로, 파생 클래스의 멤버 변수에 접근하거나 파생 클래수의 멤버 변수를 사용하는
함수를 호출해서는 안된다. 단, 파생클래스의 각 멤버를 초기화하는, 파생클래스의 어떤 멤버 함수를 호출한 후라면 상관
없다.
-- 2009-02-10 23:02:00
■ VC++ 2008 에서 "도구 => 옵션 => '프로젝트 밑 솔루션' => VC++ 디렉토리" 에서 해당 라이브러리의 헤더 파일과 라이브러
리 파일을 "포함파일" 과 "라이브러리 파일" 에 설정을 했어도 해당 경로에서 라이브러리를 못찾는 경우가 있다. 이때는
"프로젝트 => 속성" 에서 헤더 파일과 라이브러리 파일의 경로를 또 적어주어야 한다.
-- 2009-02-27 10:02:00
■ 멤버 함수 템플릿은 가상함수가 될 수 없다. -- 2009-02-28 04:21:00
■ C# 의 delegate 삼아서 std:ZNsIFace::ZIDelgtMSG 클래스를 설계하였다. 이 object 로부터 메시지를 수신하는 클래스는 이
클래스를 상속하거나, 이 클래스를 상속하여 관련 interface 를 재정의한 클래스를 멤버 변수로 가지고 있는 것이 좋다.
특히 다수의 메시지를 수신받아야 하는 경우에는 다수의 멤버 변수로 설계하는 것이 좋다.
결국 ZIDelgtMSG 에서 정한 interface 만 사용할 수 있는 것인데, 이런 때는 COM(Component Object Model) 이 참 편리하게
느껴진다. 또한 C++ 표준에도 COM 이 들어가면 좋겠다는 생각을 하게 된다.
-- 2009-03-01 12:04:00
■ 다중 쓰레드 프로그램에서 다소 긴 작업을 처리하는 작업쓰레드가 있고, 이 쓰레드에서 작업을 처리하는 동안 얼마만큼을
처리했는지 처리과정을 나타내는 진행 상황 정보 변수를 담은 object 에 자주 조회해야 한다고 해보자.
(물론, 진행 상황 정보 변수들이 동적할당이 필요없는 데이타라면 동기화가 굳이 필요없으므로, 여기서는 동적 할당이 필
요한 변수들이 있다고 가정한다.)
1) 작업쓰레드 object 에 주기적으로 polling 하는 경우,
이때는 해당 작업쓰레드에서 진행 상황 정보 object 에 진행정보변수를 설정하거나, 다른 쓰레드에서 진행 상황 정보 object
에 접근할 때에는 동기화를 해주어야 한다.
진행상황정보의 읽기 작업(즉 polling)이 갱신작업보다 상당히 많다면 읽기/쓰기 lock 을 사용하는 것도 한 방법이다.
2) 작업쓰레드 자체에서 실행 코드의 어떤 지점을 지날 때마다, 작업 진행 정보 object 를 인수로 하여, 어떤 지정된
함수를 호출하는 경우,
이처럼 작업 쓰레드 자체에서 주기적으로 어떤 함수를 호출하는 경우에는, 동기화가 필요없다. 단, 호출된 함수쪽 에서는
경우에 따라 동기화할 필요가 있을 것이다.
※ 진행 상황 정보 object 의 멤버 변수들이 불어나서 많아진다면 각각의 진행 상황 정보를 멤버 변수로 만드는 것 보다
는 key/value 의 map 으로 구성하는 것도 좋을 것 같다. 이런 목적으로
CKeyValueMap_T<> 이나 CKeyValMapPrgs(Sync)_T<>
을 설계하였다.
-- 2009-03-03 07:36:00
※ 진행 상황 정보 object 의 멤버변수에 동작할당이 필요한 문자열이 있다면, 이 문자메모리를 동적으로 할당하지 말고
문자 배열로 선언해서 사용할 수도 있겠다.
-- 2009-03-05 06:20:00
■ 서로 다른 다수의 오브젝트가, 다른 다수의 오브젝트에게 서로 다른 메시지를 송신해야 한다고 생각해보자. 각 클래스 인
터페이스를 알아야 하고 그러기 위해서는 메시지를 수신하는 클래스의 헤더를, 송신하는 클래스에서 #include 해야 하고,
또 수신하는 클래스에서 다시 송신하는 클래스에 메세지를 보낼때에는 양방향으로 #include 가 이루어져야 하는 등 포함
관계가 아주 복잡해진다. 이것을 해결하기 위해
class CKeyValueMap_T< int,std::ZNsIFace::ZIDelgtMSG*,
int,std::ZNsIFace::ZIDelgtMSG*,
/////////////////// >
클래스를 설계한다. 이 클래스를 정적object 로 갖는 클래스를 만들고, 이 클래스 헤더를 각각의 메시지 송/수신이 필요한
클래스에서 #include 하면 된다. 이 다음 각 메시지 별로 std::ZNsIFace::ZIDelgtMSG 을 상속하는 클래스를 정의하여 사용하자.
-- 2009-03-06 08:59:00
■ Modeless 대화상자에서 Modeless 대화상자를 호출한 부모 윈도우에서 쓰레드가 동작하고 있는 경우, 부모창이 닫히면 Modeless
대화상자가 자동으로 안닫히는 경우가 있다. 이때는 부모창의 종료이벤트에서 명시적으로 해당 Modeless 를 종료해 주는
것이 좋다.
-- 2009-03-08 21:28:00
■ 함수 템플릿의 템플릿 인수가 템플릿인 경우에는 어떻게 전문화하는지, CStringEx.H 의 std::__FastMoveObj() 의 CStringBase_T<>
템플릿 전문화에 그 예가 있다.
-- 2009-09-06 07:26:00
■ OS 별로 별도의 코딩이 필요한 파일들
MainHead.H
MainHeadEx.H
CFileEx.H
CProcess.H
CNet.H
■ 도전과 응전을 통한 발전
인간은 누구든 현실에 안주하려는 속성을 지니고 있다. 어느 정도의 단계에 이르면 거기에 만족하고 그만 멈추려 고 한다.
그런데 인간이 처한 운명은 자꾸만 변하기 때문에 그럴 수가 없다. 운명은 인간에게 다음 단계로 올라가라고 도전장을 던
진다. 그 단계에 이르면 다른 도전이 와서 또 다음 단계로 올라가게 한다. 그렇게 죽는 순간까지 인간은 도전을 받고 살아
간다.
- 아놀드 토인비
토인비는 가혹한 자연환경이나 외적의 침입 등 어느 문명권의 존속에 대한 위험을 도전으로 정의하고, 이러한 도전에 대하
여 이들 문명권이 응전에 성공하면 그 문명권은 계속 존속 발전할 수 있고 응전에 실패하면 역사 속으로 사라진다고 주장
합니다. 재미있는 사실은 도전을 받지 못한 문명 역시 멸망의 길을 걷는다는 것입니다. 문명은 아주 살기 어려운 환경에서
발생하는 것이고, 살기 좋은 환경에서는 문명이 발생하지 않음을 알 수 있습니다.
http://phpschool.com/gnuboard4/bbs/board.php?bo_table=talkbox&wr_id=1473843&page=1
-- 2009-04-28 09:16:00
■ 템플릿 멤버 함수를 클래스 밖에서 정의하는 코드 예시.
template<typename T> struct CShow
{
static void Show(){cout<<"## show : T="<<typeid(T).name()<<endl;}
template<typename T2> static void Show2(T2);
};
template<typename T> template<typename T2>
void CShow<T>::Show2(T2){cout<<"## show : T2="<<typeid(T2).name()<<endl;}
-- 2013-05-06
■ main 함수의 반환값을 확인할 수 있다. 윈도우에서는 커맨드 라인에
echo %ERRORLEVEL%
명령을 입력하면 그 결과를 확인할 수 있고, 리눅스에서는 커맨드 라인에
echo $?
를 입력하면, 그 결과를 확인할 수 있다
☞ http://bcode.tistory.com/5
-- 2011-03-03 22:43:00
■ 코드 리뷰 체크 리스트 예. (김익환/전규현 著 '소프트웨어 개발의 모든 것' 167 page)
□ 리뷰자가 리뷰하고 있는 소스 코드를 이해하고 있는가?
□ 소스 코드가 회사의 코딩 표준을 준수하고 있는가?
□ 함수의 모든 인수가 입력용인지 출력용인지 명시되어 있는가?
□ 모든 복잡한 알고리즘에 대하여 설명이 있는가?
□ 주석 처리되어 사용되지 않은 소스 코드에 대하여, 주석 처리를 한 이유가 설명되어 있는가?
□ 정상적인 값이나 범위를 확인하기 위해서, 모든 데이타에 대하여 Assertion 을 사용하고 있는가?
□ 함수에서 리턴으로 나가는 모든 곳에서, 모든 에러를 적절히 처리하고 있는가?
□ 모든 Exception 을 제대로 처리하고 있는가?
□ 할당된 메모리를 모두 해제하고 있는가?
□ 모든 전역 변수가 thread-safe 한가?
□ 동시에 여러 쓰레드에서 액세스되는 모든 object 가 thread-safe 한가?
□ 모든 Lock 은 얻어진 순서대로 해제되고 있는가?
□ 무한 루프가 될만한 소스 코드는 없는가?
□ 소스 코드가 속도, 메모리 사용에 무리는 없는가?
□ 모든 배열의 인덱스가 배열의 크기를 넘어서 참조하지 않는가?
□ 모든 변수는 사용하기 전에 초기화하고 있는가?
□ 이미 존재하는 API 를 사용해서 대체할 수 있는 부분이 있는가?
여기에 멀티 쓰레드에 관련된 항목만 뽑아내고, 몇 가지를 더 추가하자.
□ 모든 전역 변수가 thread-safe 한가?
□ 동시에 여러 쓰레드에서 액세스되는 모든 object 가 thread-safe 한가?
□ 모든 Lock 은 얻어진 순서대로 해제되고 있는가?
□ 무한 루프가 될만한 소스 코드는 없는가?
□ 동기화 영역에서 보호되는 class 의 멤버 변수는, 해당 동기화 object 와 가까운 곳에 선언되어 있는가?
멀리 떨어져서 선언되어 있다면, 아주 골치아픈 문제가 발생할 수 있다. 이것은 아는 사람만 알 것이다.
□ 동기화 영역에서 수행되는 Flow 가 '정밀'하게 정리되어 있는가?
-- 2011-04-16 15:39:00
□ DB 에서 ERD 가 있는 것처럼, 클래스 설계도나 근거 자료가 있는가?
-- 2011-04-17 12:08:00
□ 문자열의 길이와 파일 길이, 소켓 송수신 버퍼 길이를 표현하는 정수가 적절하게 typedef 되어 있고, 일관성있게 사용
되고 있는가?
-- 2011-05-09 21:10:00
□ 소켓 송수신 버퍼 길이를 표현하는 정수의 범위를 넘어서 송수신하는 경우는 없는가.
□ 정수의 overflow 나 underflow 는 없는가.
-- 2011-05-19 09:14:00
□ 소켓 송신 시에 vector 와 관련 자료구조를 적절히 사용하여, 문자열 object 가 송신 버퍼 리스트에 전달될 때, 송신
데이타의 복사가 최소화되도록 하였는가. 가급적 문자열 object 의 문자열 메모리가 송신 버퍼 리스트로 (복사가 아닌)
이동되는 것이 좋으며, 때에 따라 송신 버퍼 리스트의 각 원소를 고정 길이 문자 배열로 구현하는 것도 좋을 수 있다.
-- 2013-06-08 15:25:00
□ 작업 구간이 일부 겹치는 경우, 동적 메모리를 사용하는 멤버 변수에 접근할 때, 적절한 동기화가 되었는가.
-- 2013-06-09 18:34:00
□ 스케줄러 쓰레드에 스케줄이 다중으로 등록되는 일은 없는가. '동해기계항공'에서 장비 모니터링 프로그램을 만들어
줄 때, 스케줄이 점점 다중 등록되어서 시간 주기가 짧아지고 로그도 점점 커지는 경우가 있었다.
또한 ABA 가 문제를 발생시키는 경우에도, 정확히 처리가 되는지 점검해야 한다.
-- 2013-06-21 19:41:00
□ 하나의 object 가 다른 작업 쓰레드에서 접근하고 사용 중일 때, 해당 object 가 다른 요인에 의해서 소멸되지 않도
록 되어 있는가. 이 때, 아래에서 설명하는 '참조 카운팅 종료'가 적용되면 좋다.
-- 2013-06-23 19:30:00
□ new[] 로 생성된 것은 delete[] 로 해제되고 있는가. 이것은 MainHead.H 의 2013-07-09 23:32:00 일자 주석을 참고.
리눅스에서라면 valgrind 로 검사하는 것도 좋다. 여기까지 오는데 참 기나긴 시간이 흐르지 않았는가.
-- 2013-07-09 23:44:00
new 나 new[] 로 생성되는 일이 아예 없어야겠다. 즉 ZtCObjectNew<> 나 CArray_T<> 등의 클래스 를 사용해야 한다.
-- 2013-07-11 01:26:00
□ 네트워크 관련 처리에서, 데이타를 수신 버퍼로 수신하는 상황에서, 수신 버퍼의 최대 크기로 수신한 경우, 더 수신할
데이타가 있는지 검사하였는가.
이 사항은 MainSSL.H 의 2015-03-06 22:17:00 일자 기록을 참고. https://www.openssl.org 의 데이타를 가져올 때, 응
답 본문을 BIO object 에서 읽어 왔는데, 최대 수신 버퍼 크기로 읽어 왔을 때의 처리가 빠져 있었다. 그래서 이상하게
본문을 끝까지 받지 못했었다.
-- 2015-03-08 21:32:00
□ 쓰레드풀 같이 object 의 풀을 사용하는 경우, object 을 풀에 반납하고 가져올 때, 종료및 초기화 처리가 되었는가.
CCtrlAsyncSock.H 파일의 "'코드C2'에 대한 주석" 참고. -- 2015-03-22 17:01:00
■ 참조 카운팅 종료
object 의 참조 카운팅이 -1 인 경우에만, 어떤 object 를 소멸시키거나, 특정 flow 를 종료하는 것이다. 어떤 object 의
참조를 다른 작업 쓰레드에서 사용하는 경우, 그 쓰레드에서 해당 object 에 접근하는 동안에는 다른 쓰레드에서 그 object
를 소멸시키면 안된다. 이런 때 사용하는 기법이다.
-- 2013-06-23 19:25:00
'참조 카운팅 종료'시에 어떤 종료 행위를 효과적으로 수행하기 위해, 참조 카운팅을 증가/감소시키는 함수는 외부 object
를 인수로 받아, 그 object 에서 일정한 행위를 수행하게 하면 좋다.
-- 2013-06-23 19:34:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
#endif //__MAINHEADER_H__