C++에는 using이라고.. class, namespace, template, virtual, operator 이런 것보다는 좀 생소하고 덜 쓰이는 키워드가 있다.
일반적인 프로그래머라면 타이핑 수고를 덜기 위해서 using namespace std; 정도 선언할 때나 사용했던 게 전부일 것이다.

얘는 C의 키워드로 치면 그나마 typedef와 성격이 얼추 비슷해 보인다. typedef는 여러 토큰으로 구성된 복잡한 타입 명칭을 한 단어(식별자) 한 토큰으로 축약해 준다.
타입 명칭이란 건 unsigned long처럼 예약어만으로도 두 단어 이상으로 구성될 수 있으며, 포인터형 *이라든가 const/volatile modifier 등이 붙어서 더욱 복잡해질 수 있다.

그러니 이런 걸 축약하는 기능은 단순히 토큰을 기계적으로 치환하는 #define 전처리기 계층이 아니라 컴파일러 계층에서 반드시 필요하다. 가령, PSTR a, b를 char *a, *b로 자동으로 인식되게 바꾸는 것은 #define만으로는 문법적으로 불가능하기 때문이다. 더구나 함수의 포인터 타입은.. 가리키는 함수가 받아들이는 인자들의 개수와 타입을 일일이 그런 식으로 나열해야 한다~!

C에서는 구조체형 변수를 선언할 때 반드시 struct를 일일이 붙여서 struct ABC 이런 식으로 선언해야 했다. struct를 생략하고 바로 ABC 한 단어만으로 쓰려면 이것조차도 typedef를 해 줘야 됐다.
그러니 C에서는 구조체를 typedef struct _ABC { ... } ABC; 이렇게 두벌일을 하면서 선언하는 게 관행이었으나..

C++에서는 객체지향 이념이 강화되면서 번거롭게 typedef를 안 해도 struct/class를 생략하고 곧바로 그 타입을 쓸 수 있게 됐다. 사실 이게 당연하고 더 자연스러운 조치가 아닌가 생각한다.

뭐 아무튼 typedef는 그런 중요한 역할을 하는 물건이다.
typedef를 통해 새로 만들어진 명칭은 사람이 보기에만 서로 다를 뿐, 컴파일러의 입장에서는 서로 완전히 동치이다. 전문 용어로 표현하자면 syntactic sugar이다.

내부적으로 담고 있는 물건은 동일하지만(똑같은 정수??) 서로 다른 타입으로 취급되어서 명시적인 형변환 없이는 서로 덥석 대입되지 않는 파생 타입.. 이런 걸 생성할 수 있으면 좋을 텐데 C/C++에서는 그게 쉽지 않다.
그러니 unsigned short/int와는 미묘하게 다른 wchar_t 같은 타입은 컴파일러가 언어 차원에서 직통으로 지원해 주지 않으면 사용자가 만들어 내기 난감하다.

그리고 HWND, HMODULE처럼 서로 호환되지 않는 다양한 핸들 타입도 내부적으로는 dummy 구조체의 포인터형을 일일이 typedef하는 편법을 동원해야 선언할 수 있다.
마치 include guard 삽질을 대체하기 위해 #pragma once가 사실상의 표준 형태로 등극한 것처럼.. 저것도 앞으로는 C++ 언어 차원에서 개선되어야 할 점이 아닌가 한다. 정수형에 대해서는 부분적이나마 type safety를 강화하려고 정수와 무작정 호환되지 않는 enum class 같은 것도 2010년대 들어서 도입된 바 있다.

아무튼, typedef는 통상적인 사유로 인해 길어진 type 명칭을 한데 줄이며, 축약된 명칭을 현재의 scope에다 도입해 준다.
그런데 using도 긴 명칭을 줄여 준다는 점에서는 역할이 비슷하다. 단지 그 배경이 typedef와는 완전히 다를 뿐이다.
바로, 지금 문맥과는 다른 namespace에 속한 명칭을 일일이 namespace를 명시하지 않고도 곧장 참조 가능하게 해 준다. 뭐, 개념은 그러하지만 구체적인 세부 문법과 용례는 생각보다 복잡하며, 본인 역시 이를 다 정확하게 알지는 못한다.

using은 크게 선언(declaration)과 지시(directive)라는 두 형태로 나뉘어서 문법적으로 서로 다르게 취급된다. 전자는..

using std::vector;

이런 식으로 구체적인 명칭을 써 주는 형태이다. 위의 경우 이 scope에서는 이제 앞에 std::를 안 붙여도 vector 클래스를 쓸 수 있게 된다. 사용되는 곳이 클래스의 내부라면 굳이 namespace 말고 기반 클래스 같은 타 클래스의 이름이 들어와도 된다.

std::vector를 vector로 줄여 쓰는 것은 기존의 #define이나 typedef로 가능하지 않다. 특히 typedef의 경우,

typedef std::vector<int> vector; //????

템플릿 인자가 모두 주어져서 온전한 type으로 실현된 놈이라면 저렇게 단축 명칭을 부여할 수 있겠지만, 그렇지 않은 추상적인 명칭을 축약하지는 못하기 때문이다. C++의 상속과 연계를 위해 dynamic_cast가 도입된 것처럼, C++에서 도입된 다단계 scope과의 연계를 위해 예전에는 없던 완전히 새로운 명칭 축약 기능이 필요해진 셈이다.

그리고 후자인 using 지시는.. using namespace라는 두 단어로 시작하여 이 namespace에 속하는 모든 명칭들을 곧장 자동 개방해 버린다.
선언이건 지시건 하는 일은 별 차이가 없다. 이것도 그냥 와일드카드에 속하는 ... 이나 * 를 써서 using std::...; 같은 선언으로 통합해 버려도 될 것 같은데, 미관상 보기 안 좋아서 그렇게 안 했나 보다.

물론 일부러 구분해 놓은 걸 당장 쓰기 편하다는 이유로 몽땅 개방해서 내 명칭과 뒤섞어 버리는 건 전역 변수, friend, public의 남발만큼이나 경계해야 할 일이다. 하지만 적절하게 활용하는 건 auto를 쓰는 것만큼이나 코드를 짧고 간결하게 만드는 약이 될 수도 있다.

C++ 표준 라이브러리의 경우 namespace가 도입되기 전 코드와의 호환을 지키기 위해 <iostream.h>는 std로 감싸져 있지 않고, <iostream>은 감싸져 있는 것으로 잘 알려져 있다. 물론 .h 버전은 앞으로 사용을 권하지 않는 deprecated로 철저히 봉인됐고 말이다.

요 두 가지가 using의 전통적인 기능이었다.
그런데 C++11 이후에는 using이 typedef의 기존 기능까지 흡수하여 본격적인 타입 alias 전담 키워드로 등극하기 시작했다. 바로, 등호를 이용해서

using P_INT = int*;
using PF_INT = int (*)();

위와 같이 써 주면 아래의 typedef와 완전히 동치가 된다.

typedef int* P_INT;
typedef int (*P_INT)();

굉장히 참신하다. 새 명칭과 치환 대상 타입이 =를 경계로 딱 분리되어 있다 보니 재래식 typedef보다 깔끔하고 알아보기도 더 쉽다.
using이라는 단어는 파스칼의 use 키워드와 비슷한 느낌이며, using A=B는 파스칼의 type A=B와 뭔가 닮은 것 같다. 또한 이 문법은 namespace에 대한 alias를 만드는 namespace A = B::C 같은 문법과도 일관성이 있다.

Visual C++에서는 한 2013쯤부터 지원되기 시작했다. 2010은 지원 안 하고, 2012는 인텔리센스 컴파일러는 지원하지만 본 컴파일러는 지원하지 않더라.
이름 없는 namespace를 선언해서 C의 static 전역 변수/함수를 표현하듯이, C++의 키워드를 이용해서 기존 C의 기능을 대체하는 예가 하나 더 생겼다. 최신 컴파일러에서는 using을 볼 일이 더 많아지겠다.

Posted by 사무엘

2018/12/15 08:32 2018/12/15 08:32
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1565

Trackback URL : http://moogi.new21.org/tc/trackback/1565

Leave a comment
« Previous : 1 : ... 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : ... 1473 : Next »

블로그 이미지

철도를 명절 때에나 떠오르는 4대 교통수단 중 하나로만 아는 것은, 예수님을 사대성인· 성인군자 중 하나로만 아는 것과 같다.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2019/01   »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Site Stats

Total hits:
1098049
Today:
208
Yesterday:
378