Microsoft MVP성태의 닷넷 이야기
VC++: 18. VC++ 7.0에서부터 ? : 연산자 처리가 바뀌었습니다. [링크 복사], [링크+제목 복사],
조회: 18288
글쓴 사람
정성태 (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)
12740정성태7/29/202114755오류 유형: 747. SharePoint - InvalidOperationException 0x80131509
12739정성태7/28/202115150오류 유형: 746. Azure Active Directory - IDW10106: The 'ClientId' option must be provided.
12738정성태7/28/202116096오류 유형: 745. Azure Active Directory - Client credential flows must have a scope value with /.default suffixed to the resource identifier (application ID URI).
12737정성태7/28/202115236오류 유형: 744. Azure Active Directory - The resource principal named api://...[client_id]... was not found in the tenant
12736정성태7/28/202115505오류 유형: 743. Active Azure Directory에서 "API permissions"의 권한 설정이 "Not granted for ..."로 나오는 문제
12735정성태7/27/202115281.NET Framework: 1081. C# - Azure AD 인증을 지원하는 데스크톱 애플리케이션 예제(Windows Forms) [2]파일 다운로드1
12734정성태7/26/202132100스크립트: 20. 특정 단어로 시작하거나/끝나는 문자열을 포함/제외하는 정규 표현식 - Look-around
12733정성태7/23/202120044.NET Framework: 1081. Self-Contained/SingleFile 유형의 .NET Core/5+ 실행 파일을 임베딩한다면? [1]파일 다운로드2
12732정성태7/23/202113459오류 유형: 742. SharePoint - The super user account utilized by the cache is not configured.
12731정성태7/23/202115515개발 환경 구성: 584. Add Internal URLs 화면에서 "Save" 버튼이 비활성화 된 경우
12730정성태7/23/202116981개발 환경 구성: 583. Visual Studio Code - Go 코드에서 입력을 받는 경우
12729정성태7/22/202115420.NET Framework: 1080. xUnit 단위 테스트에 메서드/클래스 수준의 문맥 제공 - Fixture
12728정성태7/22/202115506.NET Framework: 1079. MSTestv2 단위 테스트에 메서드/클래스/어셈블리 수준의 문맥 제공
12727정성태7/21/202116595.NET Framework: 1078. C# 단위 테스트 - MSTestv2/NUnit의 Assert.Inconclusive 사용법(?) [1]
12726정성태7/21/202116380VS.NET IDE: 169. 비주얼 스튜디오 - 단위 테스트 선택 시 MSTestv2 외의 xUnit, NUnit 사용법 [1]
12725정성태7/21/202114895오류 유형: 741. Failed to find the "go" binary in either GOROOT() or PATH
12724정성태7/21/202117807개발 환경 구성: 582. 윈도우 환경에서 Visual Studio Code + Go (Zip) 개발 환경 [1]
12723정성태7/21/202114571오류 유형: 740. SharePoint - Alternate access mappings have not been configured 경고
12722정성태7/20/202114340오류 유형: 739. MSVCR110.dll이 없어 exe 실행이 안 되는 경우
12721정성태7/20/202115557오류 유형: 738. The trust relationship between this workstation and the primary domain failed. - 세 번째 이야기
12720정성태7/19/202114879Linux: 43. .NET Core/5+ 응용 프로그램의 Ubuntu (Debian) 패키지 준비
12719정성태7/19/202114046오류 유형: 737. SharePoint 설치 시 "0x800710D8 The object identifier does not represent a valid object." 오류 발생
12718정성태7/19/202114063개발 환경 구성: 581. Windows에서 WSL로 파일 복사 시 root 소유권으로 적용되는 문제파일 다운로드1
12717정성태7/18/202114252Windows: 195. robocopy에서 파일의 ADS(Alternate Data Stream) 정보 복사를 제외하는 방법
12716정성태7/17/202115354개발 환경 구성: 580. msbuild의 Exec Task에 robocopy를 사용하는 방법파일 다운로드1
12715정성태7/17/202122506오류 유형: 736. Windows - MySQL zip 파일 버전의 "mysqld --skip-grant-tables" 실행 시 비정상 종료 [1]
... 46  47  [48]  49  50  51  52  53  54  55  56  57  58  59  60  ...