Microsoft MVP성태의 닷넷 이야기
VC++: 18. VC++ 7.0에서부터 ? : 연산자 처리가 바뀌었습니다. [링크 복사], [링크+제목 복사],
조회: 18322
글쓴 사람
정성태 (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

비밀번호

댓글 작성자
 




... 61  62  63  [64]  65  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12339정성태9/21/202017134오류 유형: 655. 코어 모드의 윈도우는 GUI 모드의 윈도우로 교체가 안 됩니다.
12338정성태9/21/202017095오류 유형: 654. 우분투 설치 시 "CHS: Error 2001 reading sector ..." 오류 발생
12337정성태9/21/202018221오류 유형: 653. Windows - Time zone 설정을 바꿔도 반영이 안 되는 경우
12336정성태9/21/202021608.NET Framework: 942. C# - WOL(Wake On Lan) 구현
12335정성태9/21/202030794Linux: 31. 우분투 20.04 초기 설정 - 고정 IP 및 SSH 설치
12334정성태9/21/202015398오류 유형: 652. windbg - !py 확장 명령어 실행 시 "failed to find python interpreter"
12333정성태9/20/202015719.NET Framework: 941. C# - 전위/후위 증감 연산자에 대한 오버로딩 구현 (2)
12332정성태9/18/202018712.NET Framework: 940. C# - Windows Forms ListView와 DataGridView의 예제 코드파일 다운로드1
12331정성태9/18/202017625오류 유형: 651. repadmin /syncall - 0x80090322 The target principal name is incorrect.
12330정성태9/18/202018779.NET Framework: 939. C# - 전위/후위 증감 연산자에 대한 오버로딩 구현 [2]파일 다운로드1
12329정성태9/16/202021098오류 유형: 650. ASUS 메인보드 관련 소프트웨어 설치 후 ArmouryCrate.UserSessionHelper.exe 프로세스 무한 종료 현상
12328정성태9/16/202020030VS.NET IDE: 150. TFS의 이력에서 "Get This Version"과 같은 기능을 Git으로 처리한다면?
12327정성태9/12/202018173.NET Framework: 938. C# - ICS(Internet Connection Sharing) 제어파일 다운로드1
12326정성태9/12/202017567개발 환경 구성: 516. Azure VM의 Network Adapter를 실수로 비활성화한 경우
12325정성태9/12/202016761개발 환경 구성: 515. OpenVPN - 재부팅 후 ICS(Internet Connection Sharing) 기능이 동작 안하는 문제
12324정성태9/11/202017608개발 환경 구성: 514. smigdeploy.exe를 이용한 Windows Server 2016에서 2019로 마이그레이션 방법
12323정성태9/11/202016854오류 유형: 649. Copy Database Wizard - The job failed. Check the event log on the destination server for details.
12322정성태9/11/202020192개발 환경 구성: 513. Azure VM의 RDP 접속 위치 제한 [1]
12321정성태9/11/202015935오류 유형: 648. netsh http add urlacl - Error: 183 Cannot create a file when that file already exists.
12320정성태9/11/202018020개발 환경 구성: 512. RDP(원격 데스크톱) 접속 시 비밀 번호를 한 번 더 입력해야 하는 경우
12319정성태9/10/202017353오류 유형: 647. smigdeploy.exe를 Windows Server 2016에서 실행할 때 .NET Framework 미설치 오류 발생
12318정성태9/9/202016357오류 유형: 646. OpenVPN - "TAP-Windows Adapter V9" 어댑터의 "Network cable unplugged" 현상
12317정성태9/9/202019642개발 환경 구성: 511. Beats용 Kibana 기본 대시 보드 구성 방법
12316정성태9/8/202017541디버깅 기술: 170. WinDbg Preview 버전부터 닷넷 코어 3.0 이후의 메모리 덤프에 대해 sos.dll 자동 로드
12315정성태9/7/202019835개발 환경 구성: 510. Logstash - FileBeat을 이용한 IIS 로그 처리 [2]
12314정성태9/7/202020033오류 유형: 645. IIS HTTPERR - Timer_MinBytesPerSecond, Timer_ConnectionIdle 로그
... 61  62  63  [64]  65  66  67  68  69  70  71  72  73  74  75  ...