가장 성가신 해석

Most vexing parse

가장 성가신 해석은 C++ 프로그래밍 언어로 구문 모호성 해결의 반직관적인 형태입니다.특정 상황에서 C++ 문법은 객체 파라미터의 작성과 함수 타입의 지정을 구별할 수 없습니다.이러한 경우 컴파일러는 해당 행을 함수 유형 사양으로 해석해야 합니다.

발생.

"가장 짜증나는 해석"이라는 용어는 Scott Meyers가 2001년에 쓴 의 저서 Effective [1]STL에서 처음 사용되었습니다.C에서는 이례적인 현상이지만 C++[2]11에서는 균일한 초기화가 도입될 때까지 C++에서는 매우 일반적인 현상이었습니다.

C스타일의 캐스트

함수 캐스트가 변수를 초기화하기 위한 식을 변환하려는 경우 다음과 같은 간단한 예가 나타납니다.

무효 f(더블 my_dbl) {   인트 i(인트(my_dbl)); } 

위의 2행은 애매합니다.하나의 가능한 해석은 변수를 선언하는 것이다. i변환함으로써 생성되는 초기값으로 my_dbl에 대해서int단, C는 함수 파라미터 선언 주위에 여분의 괄호를 사용할 수 있습니다.이 경우,i는 대신 다음과 같은 함수 선언입니다.

// i라는 함수는 정수를 취하여 정수를 반환합니다. 인트 i(인트 my_dbl); 

이름 없는 임시

보다 상세한 예는 다음과 같습니다.

구조 타이머 {};  구조 타임키퍼 {   명시적 타임키퍼(타이머 t);   인트 get_time(); };  인트 주된() {   타임키퍼 time_keeper(타임키퍼)(타이머());   돌아가다 time_keeper(타임키퍼).get_time(); } 

회선

  타임키퍼 time_keeper(타임키퍼)(타이머()); 

애매한 것은 어느 쪽인가로 해석될 수 있기 때문에

  1. 변수의 변수 정의time_keeper계급의TimeKeeper, 클래스의 익명 인스턴스로 초기화되었습니다.Timer또는
  2. 함수의 함수 선언time_keeper타입의 오브젝트를 반환한다.TimeKeeper또한 단일(유형) 매개 변수를 가지며, 그 유형은 (a에 대한[Note 1]) 함수로 입력 및 반환을 받지 않습니다.Timer물건들.

C++ 표준에는 두 번째 해석이 필요하며, 이는 위의 9행과 일치하지 않습니다.예를 들어 Clang++는 가장 성가신 해석이 9번째 줄에 적용되어 다음 [3]줄에 오류가 발생했음을 경고합니다.

$ clang + + time _ keeper . cc timekeeper.cc:9:25 : warning : 괄호가 함수 선언 [ - Wvexing - parse ]TimeKeeper ( Timer ) ; ^ ~~~~ timekeeper.cc:9:26 :주: 변수 TimeKeeper Time_keeper ( Timer ) ; ^ ~ ~ ~ ~ ~ ^ ( ) )의 시간을 선언하기 위해 괄호를 추가합니다.er.cc:10:21: 오류: 회원 참조 기반 유형 'TimeKeeper (Timer (*))'가 구조 또는 유니언 반환 time_keeper.get_time()이 아닙니다. ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

솔루션

이러한 애매한 선언에 대한 필요한 해석은 의도된 [4][5]것이 거의 아니다.C++의 함수 유형은 보통 typedef 뒤에 숨겨지며 일반적으로 명시적인 참조 또는 포인터 한정자를 가집니다.대체 해석을 강제하기 위해 일반적인 방법은 다른 객체 생성 또는 변환 구문입니다.

유형 변환 예제에서는 캐스트에 사용할 수 있는 두 가지 대체 구문이 있습니다. "C-style cast"

// 유형 int 변수를 선언합니다. 인트 i((인트)my_dbl); 

또는 이름 있는 출연자:

인트 i(static_cast< >인트>(my_dbl)); 

변수 선언 예에서는 (C++11 이후) 권장되는 방식은 균일한(괄호) [6]초기화입니다.이것에 의해, 타입명 전체를 생략할 수도 있습니다.

//다음 작업 중 하나: 타임키퍼 time_keeper(타임키퍼)(타이머{}); 타임키퍼 time_keeper(타임키퍼){타이머()}; 타임키퍼 time_keeper(타임키퍼){타이머{}}; 타임키퍼 time_keeper(타임키퍼)(     {}); 타임키퍼 time_keeper(타임키퍼){     {}}; 

C++11 이전에는 의도한 해석을 강제하기 [5]위한 일반적인 기술은 추가 괄호 또는 복사 초기화였습니다.

타임키퍼 time_keeper(타임키퍼)( /*MVP 회피*/ (타이머()) ); 타임키퍼 time_keeper(타임키퍼) = 타임키퍼(타이머()); 

후자의 구문에서는 복사 초기화[7]컴파일러에 의해 최적화될 가능성이 있습니다.C++17 이후, 이 최적화는 [8]보증되고 있습니다.

메모들

  1. ^ C++형 붕괴규칙에 따르면 파라미터로 선언된 함수 객체는 해당 유형의 함수에 대한 포인터와 동등하다."함수 객체" 참조#C와 C++.

레퍼런스

  1. ^ Meyers, Scott (2001). Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library. Addison-Wesley. ISBN 0-201-74962-9.
  2. ^ Coffin, Jerry (29 December 2012). "c++ - What is the purpose of the Most Vexing Parse?". Stack Overflow. Archived from the original on 17 January 2021. Retrieved 2021-01-17.
  3. ^ Lattner, Chris (5 April 2010). "Amazing Feats of Clang Error Recovery". LLVM Project Blog. The Most Vexing Parse. Archived from the original on 26 September 2020. Retrieved 2021-01-17.
  4. ^ DrPizza; Prototyped; wb; euzeka; Simpson, Homer J (October 2002). "C++'s "most vexing parse"". ArsTechnica OpenForum. Archived from the original on 20 May 2015. Retrieved 2021-01-17.
  5. ^ a b Boccara, Jonathan (2018-01-30). "The Most Vexing Parse: How to Spot It and Fix It Quickly". Fluent C++. Retrieved 2021-01-17.
  6. ^ Stroustrup, Bjarne (19 August 2016). "C++11 FAQ". www.stroustrup.com. Uniform initialization syntax and semantics. Retrieved 2021-01-17.
  7. ^ "Myths and urban legends about C++". C++ FAQ. What is copy elision? What is RVO?. Archived from the original on 17 January 2021. Retrieved 2021-01-17.
  8. ^ Devlieghere, Jonas (2016-11-21). "Guaranteed Copy Elision". Jonas Devlieghere. Retrieved 2021-01-17. 단, 에 기재되어 있는 경고에 주의해 주십시오.

외부 링크