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

비밀번호

댓글 작성자
 




... [106]  107  108  109  110  111  112  113  114  115  116  117  118  119  120  ...
NoWriterDateCnt.TitleFile(s)
11308정성태9/13/201720996VS.NET IDE: 121. 비주얼 스튜디오에서 일부 텍스트 파일을 무조건 메모장으로만 여는 문제파일 다운로드1
11307정성태9/13/201723498오류 유형: 421. System.Runtime.InteropServices.SEHException - 0x80004005
11306정성태9/12/201721642.NET Framework: 682. 아웃룩 사용자를 위한 중국어 스팸 필터 Add-in
11305정성태9/12/201723137개발 환경 구성: 334. 기존 프로젝트를 Visual Studio를 이용해 Github의 신규 생성된 repo에 올리는 방법 [1]
11304정성태9/11/201720042개발 환경 구성: 333. 3ds Max를 Hyper-V VM에서 실행하는 방법
11303정성태9/11/201723547개발 환경 구성: 332. Inno Setup 파일의 관리자 권한을 제거하는 방법
11302정성태9/11/201719436개발 환경 구성: 331. SQL Server Express를 위한 방화벽 설정
11301정성태9/11/201717716오류 유형: 420. SQL Server Express 연결 오류 - A network-related or instance-specific error occurred while establishing a connection to SQL Server.
11300정성태9/10/201722492.NET Framework: 681. dotnet.exe - run, exec, build, restore, publish 차이점 [3]
11299정성태9/9/201721160개발 환경 구성: 330. Hyper-V VM의 Internal Network를 Private 유형으로 만드는 방법
11298정성태9/8/201724703VC++: 119. EnumProcesses / EnumProcessModules API 사용 시 주의점 [1]
11297정성태9/8/201721290디버깅 기술: 96. windbg - 풀 덤프에 포함된 모든 닷넷 모듈을 파일로 저장하는 방법
11296정성태9/8/201724062웹: 36. Edge - "이 웹 사이트는 이전 기술에서 실행되며 Internet Explorer에서만 작동합니다." 끄는 방법
11295정성태9/7/201721971디버깅 기술: 95. Windbg - .foreach 사용법
11294정성태9/4/201721527개발 환경 구성: 329. 마이크로소프트의 CoreCLR 프로파일러 예제 빌드 방법 [1]
11293정성태9/4/201722167개발 환경 구성: 328. Visual Studio(devenv.exe)를 배치 파일(.bat)을 통해 실행하는 방법
11292정성태9/4/201720320오류 유형: 419. Cannot connect to WMI provider - Invalid class [0x80041010]
11291정성태9/3/201721539개발 환경 구성: 327. 아파치 서버 2.4를 위한 mod_aspdotnet 마이그레이션
11290정성태9/3/201725349개발 환경 구성: 326. 아파치 서버에서 ASP.NET을 실행하는 mod_aspdotnet 모듈 [2]
11289정성태9/3/201723042개발 환경 구성: 325. GAC에 어셈블리 등록을 위해 gacutil.exe을 사용하는 경우 주의 사항
11288정성태9/3/201719733개발 환경 구성: 324. 윈도우용 XAMPP의 아파치 서버 구성 방법
11287정성태9/1/201728845.NET Framework: 680. C# - 작업자(Worker) 스레드와 UI 스레드 [11]
11286정성태8/28/201716341기타: 67. App Privacy Policy
11285정성태8/28/201724916.NET Framework: 679. C# - 개인 키 보안의 SFTP를 이용한 파일 업로드파일 다운로드1
11284정성태8/27/201723117.NET Framework: 678. 데스크톱 윈도우 응용 프로그램에서 UWP 라이브러리를 이용한 비디오 장치 열람하는 방법 [1]파일 다운로드1
11283정성태8/27/201718748오류 유형: 418. CSS3117: @font-face failed cross-origin request. Resource access is restricted.
... [106]  107  108  109  110  111  112  113  114  115  116  117  118  119  120  ...