새해 첫 출근날부터 질렀다. 올해도 지름에게 자유롭지 못한한해가 될듯 -_-;
첫빠따는 자전거 부품.. 허브다이나모 SON20.
쉽게 말하면 자전거용 발전기다 -_-;
바퀴를 아직 짜기전이니까 그냥 허브만 자전거에 달아서 테스트..
램프도 없으니 브롬톤꺼 잠시 빌려서 연결...
로드용 허브다이나모라 , 브롬톤용보다 확실히 크다.
손이 안보이게 돌리면 불이 들어옴!
폴리건에 버택스를 추가한다던지 같은 작업을 긴 라인동안 반복하게되면 나도 모르게 좀 깔끔하게 만들고 싶어진다.
// Sample , Ogre에서 ManualObject 설정하는 경우..
position( 0 , 0 );
textureCoord( 0 , 1 );
colour( 1 , 1 , 1 , 1 );
position( 1 , 0 );
textureCoord( 0 , 1 );
colour( 1 , 1 , 1 , 1 );
position( 0 , 1 );
textureCoord( 0 , 1 );
colour( 1 , 1 , 1 , 1 );
....
이럴때 같은 인자들을 묶고 다른것들만 넣어서
AddVertex( 0 , 0 , 0 , 1 );
AddVertex( 1 , 0 , 0 , 1 );
....
이런식으로 정리하고싶어진다.
정리하는 방법이 여러가지가 있는데 , 아에 AddVertex함수를 원래 클래스에 추가하는 방법이 있지만 , 엔진단에서 건드리는 경우가 될수도 있고 , 보통 로컬로 간단히 작업하는 부분이기때문에 요 파일 내에서 해결하는게 좋다.
일반적인 해결 방안은 전처리기( define )을 이용하는 방법이다.
#define AddVertex( x , y , u , v ) { \
position( x , y );\
textureCoord( u , v );\
colour( 1 , 1 , 1 , 1 );\
}
이걸로 정리가 가능하다.
만세
라고 생각하면 오산..
개인적으로 define을 싫어한다. 디버그할때 구체적인 에러위치 파악하기가 어렵고 , 특히 이런 define을 이용한 펑션처럼 구현하는걸 꺼린다. 쓸수있다면 inline을 쓰고 싶다.
inline void AddVertex( float x , float y , float u , float v )
{
position( x , y );
textureCoord( u , v );
colour( 1 , 1 , 1 , 1 );
}
오 아름답다. 하지만 큰 문제가 있다. 컴파일하면 에러가난다.
'AddVertex' : local function definitions are illegal
C++ 에서 펑션 내부에 펑션 정의를 허용하지 않는다. 왜 인라인도 안되냐고.
결국 이 인라인 펑션을 글로벌로 빼야하는데 , 어차피 일부분에만 사용하는 펑션을 글로벌로 빼는 것이 영 탐탁치 않다. 어떻게든 안에서 해결하고 싶다.
Try One
핵심 아이디어는 펑션 내부의 함수 선언은 불가지만 스트럭쳐나 클래스 선언은 허용된다는 점이다. 즉 , 스트럭쳐를 선언하고 그 내부에 펑션을 만들어서 사용하는것이 가능하다는 소리다.
코드의 간편화를 위해 만들고 싶은 펑션을 아래걸로 생각하겠다.
void Function( int n )
{
printf( "%d\n" , n );
}
클래스의 맴버 펑션으로 구현을 우선 해보면
struct Function
{
void Do( int n ) { printf( "%d\n" , n ); }
};
대충 이렇게 구현이 될텐데..
사용법은 2가지다.
Function fun;
fun.Do( 1 );
or
Function().Do( 1 );
둘다 그다지 아름답지 않다 -_-.
이미 원하는 펑션의 이름이 있으므로 중복해서 네이밍을 해야하는것이 눈에 띄고 무엇보다 길고 괄호가 많아서 짜증난다.
Try Two
static function을 이용하면 조금(?) 간소화가 가능하다.
struct Function
{
static void Do( int n ) { printf( "%d\n" , n ); }
};
사용은
Function::Do( 1 );
그나마 조금 낫다. -_-
Try Three
그러나 내가 원하는건 딱 Function 으로 실행을 하는건데... 여기서 전처리기의 도움을 살짝 받으면 조금 나아진다.
#define FunctionFunction::Do
Function( 1 );
오오 된다.
Try Four
Static펑션을 사용하는 불합리함이 있으므로 저방법도 되긴하나 그다지 만족 스럽지 않다. 가능하면 내부에서 모든것을 해결하고 싶다. 그래서 operator() 를 이용한 방법을 써봤다. 개인적으로 펑션 포인터를 사용하는 구조 대신 이 operator() 를 이용하는걸 좋아한다.
struct Function
{
void operator()( int n ) { printf( "%d\n" , n ); }
};
사용법은
Function a;
a( 1 ); // ok
Function()( 1 ); // ok
// Function( 1 ); // ERROR
인스턴스화를 하지 않으면 펑션을 사용하지 못하는 단점 , 그리고 두번째 호출방식은 괄호가 중복으로 들어가는 단점이 있다.. 이걸 Try Three 방식을 적용해서
#define FunctionFunction()
사용
Function( 1 )
오 -_-;; 되긴 된다.
전체적으로 정리해서 보면
struct Function
{
void operator()( int n ) { printf( "%d\n" , n ); }
};
#define Function Function()
......; 해결은 됐는데 그다지 아름답지 않다 -_-;... 뻘짓은 계속!
Try Five
번쩍 떠올랐따. 니미 ; 생성자 이용하면 더 간단하잖아!
struct Function
{
Function( int n ) { printf( "%d\n" , n ); }
};
Function( 1 );
오오 간단하다. 하지만 만약 리턴값이 필요한 경우라면 사용 할 수가 없다. 리턴값이 필요 없는 경우라면 이걸로 덕질을 종료할 수 있는 상황이지만.. 리턴도 받아야 돼!
Try Six
두 인자 더해서 리턴하는 함수로 예제를 바꾸자
int Add( int left , int right )
{
return left + right;
}
자자 리턴을 받을려면 어떻게 해야할까.
잠시고민 하다가 내린결론 , Type Casting Operator Overloading.
struct Function
{
typedef int RETURN_TYPE; // Generic Programming!!
Function( int left , int right )
{
nReturn = left + right;
}
operator RETURN_TYPE() { return nReturn; }
RETURN_TYPE nReturn; // 리턴값
};
int a = Function( 1 , 2 );
와 되긴 됐다. orz;;
이게 뭥미;;
결국 나만 알아보는 코드가 만들어져 버렸다. -_-;;;
자자 -_-;; 하는김에 좀더 해보자! 뻘짓 뻘짓
Try Seven
내친김에 InFunction의 베이스 클래스도 만들어보자. Type Casting Overloading을 베이스 클래스에서 처리해 보자 라는 데서 스타트..
virtual Ret Do( Param1 left , Param2 right ) = 0; // Pure Virtual Function
operator Ret() { return mReturn; }
protected:
Ret mReturn; // 리턴값
};
아싸 거창하다. 여차하면_인자_갯수만큼_베이스클래스_만들_태세.jpg
그리고 펑션 내부에서 사용은
struct Function : public InFunctionModule< int , int , int >
{
int Do( int left , int right )
{
return left + right;
}
};
int a = Function( 1 , 2 );
아싸 뭔가 그럴싸하다. 그런데 안된다. -_- Function 에서 InFunctionModule로 생성자 인자 전달이 자동으로 되지 않는다. 그리고 그렇다 하더라도 큰 문제점이 하나있다. 프로그램 좀 해본 사람이라면 바로 눈에 들어올 듯. Pure Virtual Function을 Base Class의 Constructor 에서 호출하는 오류는 범했다. ( Effective C++ 참조 )
Try Eight
Try Seven의 문제를 해결해봤다. 결국 캐스팅하는 부분만 남기고 나머진 다 대피.
template < typename Ret >
struct InFunctionModule
{
typedef Ret ReturnType;
void Return( ReturnType r ){ mReturn = r; }
operator ReturnType() { return mReturn; }
protected:
ReturnType mReturn; // 리턴값
};
사용하는 곳은
struct Function : public InFunctionModule< int >
{
Function( int left , int right )
{
Return( left + right );
}
};
int a = Function( 1 , 2 );
오오 ... 이런 나중에 나도 못 알아볼 코드 같으니 orz
Conclusion
프로그램은 누가봐도 눈에 잘 들어오게 짜는게 장땡이라고 생각한다.
그래서 이런 뻘짓은 제가 한걸로 충분하니 하지 마시고 -_-;
그나마 여기서 쓸만한 결론은 Try Five 밖에 없는거 같다.
어차피 로컬로 내부의 문제만 어떻게 짜든 무슨 상관이랴 -_-; 개중에 제일 깔끔하다.
펑션내부에 펑션은 C내부 구조적인 문제때문에 허용을 하지 않는다고 알고 있는데 , 스트럭쳐가 허용이 되는거면 굳이 막아둘 필요도 없지 않나 란 생각도 든다.