Microsoft MVP성태의 닷넷 이야기
VC++: 18. VC++ 7.0에서부터 ? : 연산자 처리가 바뀌었습니다. [링크 복사], [링크+제목 복사],
조회: 18324
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

VC++ 6.0에서는 다음 소스를 컴파일하는 데 오류가 없다면서... 어떤 분이 질문을 하셨습니다.

  #include <fstream>
  #include <iostream>

  template <typename IN, typename OUT>
  void Process(IN &in, OUT &out)
  {
      out << in.rdbuf();
  }

  int main(int argc, char *argv[])
  {
   using namespace std;

   fstream in, out;
   if(argc > 1) in.open(argv[1], ios::in | ios::binary);
   if(argc > 2) out.open(argv[2], ios::out | ios::binary);

   // 에러나는곳
   Process( in.is_open()? in : cin, out.is_open()? out : cout );

   return 0;
  }

하지만, VC++ 7.0에서는 다음과 같은 오류가 난다고.
--------------------------------------------------------------------------
  VC6과 Dev C++에서는 컴파일 됩니다.
  그런데 VC.NET 2003에서는 컴파일러 에러가 나네요

  e:\Temp Projects\DevCpp\main.cpp(29) : error C2446: ':' : 'std::istream'에서
  'std::fstream'(으)로 변환되지 않았습니다.
          소스 형식을 가져올 수 있는 생성자가 없거나 생성자 오버로드 확인이
  모호합니다.
  e:\Temp Projects\DevCpp\main.cpp(30) : error C2446: ':' : 'std::ostream'에서
  'std::fstream'(으)로 변환되지 않았습니다.
          소스 형식을 가져올 수 있는 생성자가 없거나 생성자 오버로드 확인이
  모호합니다.

  표준에 의하면 에러가 나지 않는것이 정상입니다.
  왜 이러지요? VC.NET으로 버전업 되면서 표준을 더 안지키게 됐나여?
--------------------------------------------------------------------------


어찌 보면, template 관련한 소스라서 VC++ 7.0이 표준을 지키지 않는 것처럼 보입니다. (엄밀히, 컴파일이 안된다는 사실은 표준에서 벗어났다고 말할 수 있습니다.)

개인적으로, 표준 스펙 같은 것에는 그다지 관심이 없기 때문에 "표준"에 비춰서 그러한 문제를 분석하는 것은 별로 하고 싶지 않습니다. 단지, 재미있는 문제였고 질문하신 분이 제공한 소스도 간단해서 직접 실행해 보면서 하나 하나 따져 보았습니다. 그러고 나서, 다음과 같은 답변을 했습니다.

--------------------------------------------------------------------------
참...아쉽게 되었네요. ^^; 정말 동작이 안되는군요.

저는 "표준" 같은 것과는 거리가 먼 사람이라서 정확한 스펙에 의한 "멋있는" 설명을 드리기가 좀 그렇지만.

일단, 그 부분은 STL 같은 것에 대한 세부 문법을 지원하지 않는 것과는 거리가 먼 것 같습니다.
어찌된 일인지 모르지만, 표준에 벗어난 것이, ( ? : ) 연산자가 된 것 같습니다.

 ? : 에서 두 번째와 세 번째 operand가 서로 형변환이 가능한 유형이어야 된다는 것이죠.
예를 들어 아래와 같이 오류를 재현할 수가 있습니다.


 int j = 0;
 double tet = 32.35;

 void *pT = ( j != 5 ) ? &j : &tet;


&j와 &tet가 서로간에 형변환이 불가능하기 때문에, 역시나 오류가 나게 됩니다.
이런 경우 다음과 같이 강제 형변환을 하게 되면 정상적으로 동작되는 것을 확인할 수 있습니다.

 void *pT = ( j != 5 ) ? &j : (int *)&tet;

따라서, 제시하신 그 부분에 대한 것도

 Process( in.is_open()? (istream &)in : cin, out.is_open()? (ostream &)out : cout );

위와 같이 필요한 부분에 대해서 형변환을 시켜주면 해결되게 되는 것이죠.

왜 ( ? : ) 연산자가 오퍼랜드에 대해서 상호 형변환을 강제하도록 되었는지는 ... 외부에 있는 저로서는 말씀드릴 수가 없겠네요. ^^
단지, 다소 좀 더 엄격한 "형식안정성"을 제공하려고 그 부분을 그렇게 수정하지 않았나 예상만 해봅니다.

구체적인 것은, ^^; "레드몬드" 사람들에게 물어봐야 겠습니다.
--------------------------------------------------------------------------

 .NET을 공부하면서 느낀 것이지만, 코드에서의 "형식안정성"은 상당히 중요한 부분으로 Microsoft에서 인식하고 있는 것 같습니다. 비록, ? : 연산자에 제공된 자유로움을 빼앗더라도 연산자간의 형식을 맞추도록 강요하는 것이 더 옳다고 판단했던 것 같습니다.

 참고로, VS.NET 2005에서는 기존 C++ Runtime Library 중에서 버퍼 크기가 지정되지 않은 모든 함수를 deprecated로 지정해서 사용을 안하도록 유도하고 있습니다. 그보다는 버퍼크기를 명시하는 새로운 함수를 쓰도록 하고 있는데요. (외국의 어떤 사람은,,, 도대체 Microsoft가 어떻게 표준 Runtime Library 함수를 "deprecated"라고 지정할 수 있는가? 라고 하신 분도 있었는데요.)

 개인적으로, C++ Runtime Library와 ? : 연산자의 그러한 변화를 "표준"이란 테두리와 상관없이 긍정적으로 바라보고 있습니다. (현재는 표준이 아니지만... 다른 컴파일러들도 그런 부분을 따라서 오히려 그것이 새롭게 "표준"으로 지정되어야 하지 않을까요?)








[최초 등록일: ]
[최종 수정일: 6/27/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 46  47  48  49  50  51  52  53  54  [55]  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12565정성태3/17/202113609오류 유형: 704. curl.exe 실행 시 dll not found 오류
12564정성태3/16/202114469VS.NET IDE: 160. 새 프로젝트 창에 C++/CLI 프로젝트 템플릿이 없는 경우
12563정성태3/16/202117390개발 환경 구성: 551. C# - JIRA REST API 사용 정리 (3) jira-oauth-cli 도구를 이용한 키 관리
12562정성태3/15/202118103개발 환경 구성: 550. C# - JIRA REST API 사용 정리 (2) JIRA OAuth 토큰으로 API 사용하는 방법파일 다운로드1
12561정성태3/12/202116876VS.NET IDE: 159. Visual Studio에서 개행(\n, \r) 등의 제어 문자를 치환하는 방법 - 정규 표현식 사용
12560정성태3/11/202117852개발 환경 구성: 549. ssh-keygen으로 생성한 PKCS#1 개인키/공개키 파일을 각각 PKCS8/PEM 형식으로 변환하는 방법
12559정성태3/11/202118150.NET Framework: 1028. 닷넷 5 환경의 Web API에 OpenAPI 적용을 위한 NSwag 또는 Swashbuckle 패키지 사용 [2]파일 다운로드1
12558정성태3/10/202117279Windows: 192. Power Automate Desktop (Preview) 소개 - Bitvise SSH Client 제어 [1]
12557정성태3/10/202115474Windows: 191. 탐색기의 보안 탭에 있는 "Object name" 경로에 LEFT-TO-RIGHT EMBEDDING 제어 문자가 포함되는 문제
12556정성태3/9/202113664오류 유형: 703. PowerShell ISE의 Debug / Toggle Breakpoint 메뉴가 비활성 상태인 경우
12555정성태3/8/202116984Windows: 190. C# - 레지스트리에 등록된 DigitalProductId로부터 라이선스 키(Product Key)를 알아내는 방법파일 다운로드2
12554정성태3/8/202116581.NET Framework: 1027. 닷넷 응용 프로그램을 위한 PDB 옵션 - full, pdbonly, portable, embedded
12553정성태3/5/202116524개발 환경 구성: 548. 기존 .NET Framework 프로젝트를 .NET Core/5+ 용으로 변환해 주는 upgrade-assistant, try-convert 도구 소개 [4]
12552정성태3/5/202116028개발 환경 구성: 547. github workflow/actions에서 Visual Studio Marketplace 패키지 등록하는 방법
12551정성태3/5/202114394오류 유형: 702. 비주얼 스튜디오 - The 'CascadePackage' package did not load correctly. (2)
12550정성태3/5/202114090오류 유형: 701. Live Share 1.0.3713.0 버전을 1.0.3884.0으로 업데이트 이후 ContactServiceModelPackage 오류 발생하는 문제
12549정성태3/4/202115512오류 유형: 700. VsixPublisher를 이용한 등록 시 다양한 오류 유형 해결책
12548정성태3/4/202116595개발 환경 구성: 546. github workflow/actions에서 nuget 패키지 등록하는 방법
12547정성태3/3/202117230오류 유형: 699. 비주얼 스튜디오 - The 'CascadePackage' package did not load correctly.
12546정성태3/3/202117103개발 환경 구성: 545. github workflow/actions에서 빌드시 snk 파일 다루는 방법 - Encrypted secrets
12545정성태3/2/202119882.NET Framework: 1026. 닷넷 5에 추가된 POH (Pinned Object Heap) [10]
12544정성태2/26/202120057.NET Framework: 1025. C# - Control의 Invalidate, Update, Refresh 차이점 [2]
12543정성태2/26/202118078VS.NET IDE: 158. C# - 디자인 타임(design-time)과 런타임(runtime)의 코드 실행 구분
12542정성태2/20/202119721개발 환경 구성: 544. github repo의 Release 활성화 및 Actions를 이용한 자동화 방법 [1]
12541정성태2/18/202117332개발 환경 구성: 543. 애저듣보잡 - Github Workflow/Actions 소개
12540정성태2/17/202118489.NET Framework: 1024. C# - Win32 API에 대한 P/Invoke를 대신하는 Microsoft.Windows.CsWin32 패키지
... 46  47  48  49  50  51  52  53  54  [55]  56  57  58  59  60  ...