Lyn
조회 수 15728 추천 수 0 댓글 3
Atachment
첨부 '3'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

이 코드는 Visual C++ 2013 RC에서 테스트 되었습니다.


C#을 자주 쓰시는 분들이라면 아시겠지만... C# 에는 @ 로 시작하는 문자열 리터럴이 있습니다.
저 안에서는 줄바꿈도 자유롭게 허용되고 Escape Sequence 할 필요도 없이 다양한 문자열을 쓸 수 있지요.
저같은 경우는 특히 쿼리를 날릴때 매우 유용하게 쓰고 있습니다.


csharpa.png


이런식으로요.


이게 C++ 할때도 참 부러웠는데... VC++ 2013 에서 드디어 사용 가능하게 되었습니다.
바로 R 접두사를 이용해서요..... 정확히는 괄호도 필요하지만


간단한 예제 만들어 보겠습니다.

#include <iostream>
#include <string>

using namespace std;

void wmain()
{
	string s = R"(Hello World
동해물과 백두산이 마르고 닳도록
\r\n\t
\가 안먹어!!
"따옴표도 그냥 써져!")";

	cout << s << endl;
}


의 실행 결과는 다음과 같습니다.


11.png


오! 멋지게 출력 되네요. (" 와 ") 가 문자열의 범위를 지정하는 태그로 쓰이는겁니다
하지만 여기 함정이 있습니다...

바로 )" 를 출력할 수 없단겁니다 (.....)

왜냐면 종료 태그로 쓰기 때문이죠.


즉 

#include <iostream>
#include <string>

using namespace std;

void wmain()
{
	string s = R"("(Test)")";

	cout << s << endl;
}


이런 코드는 오류라는 겁니다....

하지만 근성의 C++ 위원회 (...) 이번에도 그냥 넘어가지 않습니다. 
C++ 에서는 이것을 "시작 토큰 커스터마이징" 기능을 넣음으로서 해결했습니다...

이게 뭐냐면,  Raw String Literal 의 첫 ( 를 만날때 까지의 문자열을 "태그" 취급 합니다.

즉 아래와 같은 코드가 가능해집니다.


#include <iostream>
#include <string>

using namespace std;

void wmain()
{
	string s = R"Lyn("(Test)")Lyn";

	cout << s << endl;
}


RSL 의 첫 (를 만날때 까지 Lyn 이라는 문자열을 추가로 만났습니다.
그럼 위 리터럴의 시작을 나타내는 문자는 Lyn(, 종료를 나타내는 문자는 )Lyn 이 되는겁니다.
실행해보면 아래와 같습니다.


22.png


이로서 알아보긴 더럽게 힘들지만 (...) 맘껏 문자열을 만들수 있게 되었습니다.
아직 실제로 활용해보진 못햇지만, R"SQL(INSERT INTO TABLE VALUES(1, 2, 3))SQL" 처럼 이 문자열은 SQL 이다! 라는 것 처럼 표시하는식으로 사용해 볼 수 있을 것 같네요.


마지막으로 한가지... 유니코드 리터럴은 어떻게 하냐면... LR로 시작하면 끝입니다 (...) 간단하죠

TAG •
?
  • profile
    Lyn 2013.10.07 17:31
    아직 거의 쓰이지 않는 문법이라 그런지 syntax highlighter 가 제대로 컬러링을 못해주네요 =_= 젠장
  • ?
    사무엘 2013.10.08 03:27
    아아 이건 좀 내가 아는 C++과는 다른 사기적인 기능 같습니다... ㅎㅎ
    인텔리센스용 컴파일러, 코드 생성용 컴파일러, 신택스 하이라이팅용 파서 만드는 사람들.. 다 바빠지겠네요.
  • profile
    Lyn 2013.10.12 17:40
    간단하게 쓸수있는 문법이니 쓸모가 많을거 같습니다 ㅎㅎ.

Lyn
조회 수 22200 추천 수 0 댓글 0
Atachment
첨부 '5'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

이 코드는 Visual Studio 2012 Update3에서 테스트 되었습니다.


boost 1.46 부터 추가된 icl 컨테이너들은 범위를 가지는 데이터들을 넣을 수 있게 되어 있는 컨테이너다


이것들은 주로 일정 등의 데이터를 관리하기에 아주 좋게 되어 있고(boost 예제도 대부분 그런쪽입니다) 매우 확장성이 좋게 설계 되어 있어 다양한 용도로 활용 가능하지만 개인적으론 map의 기본형인 boost::icl::intervap_map<T1, T2> 의 형태가 매우 비상식적이라고 생각한다.


그래서 interval_map 을 원하는 형태로 만들어서 쓰고 싶었고 그 과정에서 알게된 것을 정리 해 본다.

내가 최종적으로 원하는 형태는 프로그램이 처음 시작할때 로딩되는 범위를 가지는 데이터를 관리 하고, 중복되는 경우가 있을경우 데이터 오류로 취급하여 예외를 발생 하는 형태입니다.


하나씩 알아보자면 interval_map 의 기본 개념은 기존의 std::map 과 같지만, 몇가지 추가적인 개념이 존재한다.

1. 구간.

구간이란 0~1, 2~3, 12:00~13:00 처럼 범위를 가지는 데이터. 수학시간에 배웠던것처럼 개구간, 폐구간, 반폐구간(좌/우) 가 존재합니다.
뭐 이건 문제될 것 없는 당연한 경우라고 보입니다.


2. Combine

입력한 구간이 서로 겹칠 경우 그 구간에 대해 Combine 동작을 시행합니다.
이것에 대해선 아래에서 마저 합니다.


3. 기본값

웃기게도 왠지 모르겠지만 (...) 기본값에 대한 처리를 변경할 수 있습니다.

여기에서 기본값이란 static T; 로 선언 했을때의 초기값입니다. int라면 0, float 라면 0.0f, std::string 이라면 길이0인 문자열인 식입니다.


1번 구간에 대해서는 별로 문제가 될 경우가 없을겁니다. 상식적으로 사용 할 수 있지요.
계속 울궈먹을 기본 코드 하나 넣겠습니다


#include <boost/icl/interval_map.hpp>
#include <string>
#include <utility>
#include <cstdio>

void wmain()
{
	using namespace std;
	using namespace boost;
	using namespace boost::icl;

	interval_map<int, wstring> ivm;

	ivm.add(make_pair(interval<int>::right_open(0, 2000), L"Right"));
	ivm.add(make_pair(interval<int>::left_open(2000, 3000), L"Left"));
	ivm.add(make_pair(interval<int>::closed(3000, 4000), L"closed"));
	ivm.add(make_pair(interval<int>::open(4000, 5000), L"Open"));

	auto it = ivm.find(1000);
	if(it != ivm.end())
	{
		wprintf(L"Find %s\n", it->second.c_str());
	}
	else
	{
		wprintf(L"Not Found");
	}
}


기본적인 사용 방법은 위와 같습니다. 구간을 지정해서 데이터를 넣고 find로 찾아오는형식으로 map과 완전히 동일합니다.

결과도 별다를게 없구요


1.png


위 코드를 자세히 보시면 3000 이라는 값은 left, closed 두개의 데이터가 겹치는 구간이라는 것을 알 수 있습니다.
이때 3000을 찾아서 출력해 보면 어떤 결과가 일어 나냐면....


2.png


이런 상황이 벌어집니다 (...) 
왜냐면 interval_map은 구간이 겹칠 경우 Combine 작업을 진행 하는데 이 단순히 interval_map<T1,T2> 로 선언한 Combine의  동작이 + 연산입니다.

즉 겹치는 구간의 데이터를 몽땅 더해서 출력해 버립니다. 숫자라면 값이 더해질것이고 문자열이라면 위처럼 문자열일 경우 두 문자열이 붙어서 나타납니다.

이 Combine 연산을 미리 몇가지 제공 하고 있는데, 이렇게 더한다던지, stl 컨테이너에 insert 를 한다던지 최대값/최소값으로 교체한던지 하는 기본적으로 많이 쓸만한 연산을 제공 하고 있습니다....만 내가 필요한 문제있을시 예외던지는 Combine은 제공 하지 않습니다.


두번째로 기본값 문제입니다. 위 코드를 수정해서 아래처럼 바꾼 후 실행해보겠습니다.


3.png



[0~2000) 구간에 빈 문자열을 넣었지만 찾을수 없다고 하고 있습니다.

왜냐면 그 Type의 기본값이 들어갈 경우 데이터를 넣지 않는것이 interval_map 기본형의 동작입니다


하지만 이 상황에서 내가 원한건 데이터 없음과, 빈 문자열을 데이터로 가지는것을 확실하게 구별 해야 하는겁니다.

값이 빈값인건 빈값이고,  없는건 없다고 할수 있어야되는 상황이더 많다고 생각되는데.... 왜 이런지는 모르겠습니다.


이 동작을 바꾸는 기능을 icl 은 제공 하고 있는데 두가지 옵션을 하나의 구조체로 만들어 총 4종류의 형태를 제공합니다.
partial_absorber, partial_enricher, total_absorber, total_enricher 의 4가지입니다.

여기서 뒤에 붙은 absorber, enricher 이 기본값을 어떻게 처리할지 결정합니다.
absorber는 날려버리고(초기형태) enricher 는 보존합니다. partial_enricher 로 바꾼 뒤 다시 한번 실행해 보겠습니다.


4.png


보다시피 찾아오는것에 성공하는 것을 볼 수 있습니다.

다음으로 앞에 붙은 partial, total 은.... 당췌 이게 어떻게 돌아가는지 모르겠습니다 =_=;;;;; 뭘로 하던 내가 원하는 동작에 지장이 없었기에 넘어갔습니다.
차후 추가적인 확인이 필요할듯 합니다. 아마 사용자 정의 type 에서만 영향을 미치는지도 모르겠습니다. 기본형은 이미 다 되어있고 ...


그리고 이제 combine 을 방지해야 하는데... combine functor 를 새로 만듬으로서 가능했습니다. 
겸사겸사 실수로 substract 를 호출하는것을 방지하기 위해 inverse functor 도 만들었습니다. 어차피 오류낼거니 궂이 따로 만들 필요는 없어서 그냥 같이 쓰도록 되었네요.


5.png


그 결과가 이 코드입니다. 중간에 less는 std::less 입니다. 비교 functor 가 템플릿에서 앞에 있는 바람에 저렇게 들어가버렷네요.

어쨋든 멋지게 assert 를 내 주네요. 원하는 동작이 만들어 졋습니다. 구간별 데이터를 안전하게 저장 할때 사용할수 있겠습니다.
궂이 사용 예를 추가해 보자면 ip 별 지역 정보를 넣어놓고 빠르게 검색할때 사용할 수 있겠네요.

TAG •
?

Board Pagination Prev 1 Next
/ 1