TL; DR
추가 괄호는 다음 컨텍스트에서 C ++ 프로그램의 의미를 변경합니다.
- 인수 종속 이름 조회 방지
- 목록 컨텍스트에서 쉼표 연산자 활성화
- 성가신 구문 분석의 모호성 해결
decltype
표현의 참조 성 추론
- 전 처리기 매크로 오류 방지
인수 종속 이름 조회 방지
표준의 부록 A에 자세히 설명 된대로 post-fix expression
형식의 (expression)
a primary expression
는이지만 id-expression
은 아니므로 unqualified-id
. 즉 (fun)(arg)
, 기존 형식에 비해 형식의 함수 호출에서 인수 종속 이름 조회가 방지됩니다 fun(arg)
.
3.4.2 인수 종속 이름 조회 [basic.lookup.argdep]
1 함수 호출 (5.2.2)의 postfix-expression이 unqualified-id 인 경우 일반적인 비 한정 조회 (3.4.1) 중에 고려되지 않은 다른 네임 스페이스를 검색 할 수 있으며, 해당 네임 스페이스에서 네임 스페이스 범위 친구 함수 또는 보이지 않는 함수 템플릿 선언 (11.3)을 찾을 수 있습니다. 검색에 대한 이러한 수정 사항은 인수 유형 (템플릿 템플릿 인수의 경우 템플릿 인수의 네임 스페이스)에 따라 다릅니다. [ 예:
namespace N {
struct S { };
void f(S);
}
void g() {
N::S s;
f(s); // OK: calls N::f
(f)(s); // error: N::f not considered; parentheses
// prevent argument-dependent lookup
}
-예제 종료]
목록 컨텍스트에서 쉼표 연산자 사용
쉼표 연산자는 대부분의 목록과 유사한 컨텍스트 (함수 및 템플릿 인수, 이니셜 라이저 목록 등)에서 특별한 의미를 갖습니다. a, (b, c), d
이러한 컨텍스트 에서 양식의 괄호는 a, b, c, d
쉼표 연산자가 적용되지 않는 일반 양식에 비해 쉼표 연산자를 활성화 할 수 있습니다.
5.18 쉼표 연산자 [expr.comma]
2 쉼표에 특별한 의미가 부여 된 문맥에서 [예 : 함수에 대한 인수 목록 (5.2.2) 및 이니셜 라이저 목록 (8.5)- 끝 예]에서 5 절에 설명 된 쉼표 연산자는 괄호 안에 만 표시 될 수 있습니다. [ 예:
f(a, (t=3, t+2), c);
세 개의 인수가 있으며 두 번째 인수의 값은 5입니다. —end example]
성가신 구문 분석의 모호성 해결
C 및 그 신비한 함수 선언 구문과의 역 호환성은 성가신 구문 분석으로 알려진 놀라운 구문 분석 모호성을 유발할 수 있습니다. 본질적으로, 선언으로 파싱 할 수있는 모든 것은 경쟁 파싱도 적용 되더라도 하나로 파싱됩니다.
6.8 모호성 해결 [stmt.ambig]
1 표현식 문과 선언을 포함하는 문법에 모호함이 있습니다 . 함수 스타일의 명시 적 유형 변환 (5.2.3)이있는 표현식 문은 맨 왼쪽 하위 표현식이 첫 번째 선언자가 ( . 이러한 경우 문은 선언입니다 .
8.2 모호성 해결 [dcl.ambig.res]
1 함수 스타일 캐스트와 6.8에 언급 된 선언 간의 유사성으로 인해 발생하는 모호성은 선언 컨텍스트에서도 발생할 수 있습니다 . 그 맥락에서 선택은 매개 변수 이름 주위에 중복 된 괄호 세트가있는 함수 선언과 이니셜 라이저로 함수 스타일 캐스트가있는 객체 선언 사이에서 선택됩니다. 6.8에 언급 된 모호함과 마찬가지로, 결의안은 선언이 될 수있는 모든 구성을 선언 으로 간주하는 것 입니다. [참고 : 선언은 비 함수 스타일 캐스트, 초기화를 나타내는 = 또는 매개 변수 이름 주위의 중복 된 괄호를 제거하여 명시 적으로 명확하게 할 수 있습니다. —end note] [예 :
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
-예제 종료]
이것에 대한 유명한 예는 그의 효과적인 STL 책 의 항목 6에서 Scott Meyers가 대중화 한 이름 인 Most Vexing Parse 입니다.
ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile), // warning! this doesn't do
istream_iterator<int>()); // what you think it does
이것은 data
반환 유형이 인 함수를 선언합니다 list<int>
. 함수 데이터는 두 개의 매개 변수를 사용합니다.
- 첫 번째 매개 변수의 이름은
dataFile
입니다. 유형은 istream_iterator<int>
입니다. 주위의 괄호 dataFile
는 불필요하며 무시됩니다.
- 두 번째 매개 변수에는 이름이 없습니다. 그 유형은 아무것도 취하지 않고
istream_iterator<int>
.
첫 번째 함수 인수 주위에 추가 괄호를 배치하면 (두 번째 인수 주위의 괄호는 불법 임) 모호성을 해결합니다.
list<int> data((istream_iterator<int>(dataFile)), // note new parens
istream_iterator<int>()); // around first argument
// to list's constructor
C ++ 11에는 여러 컨텍스트에서 이러한 구문 분석 문제를 회피 할 수있는 중괄호 이니셜 라이저 구문이 있습니다.
decltype
표현의 참조 성 추론
auto
유형 추론 과 달리 decltype
참조 (lvalue 및 rvalue 참조)를 추론 할 수 있습니다. 규칙은 decltype(e)
및 decltype((e))
표현식을 구분 합니다.
7.1.6.2 단순 유형 지정자 [dcl.type.simple]
도 4는, 발현을 위해 e
, 타입 붙이고decltype(e)
다음과 같이 정의된다 :
— e
괄호로 묶지 않은 ID 표현식이거나 괄호로 묶지 않은 클래스 멤버 액세스 (5.2.5) 인 경우 decltype(e)
는에서 명명 된 엔티티의 유형입니다 e
. 그러한 엔티티가 없거나 e
오버로드 된 함수 집합의 이름을 지정하면 프로그램이 잘못된 것입니다.
— 그렇지 않은 경우 e
xvalue이면 decltype(e)
is T&&
, 여기서 T
is 유형은 e
;
— 그렇지 않으면, e
lvalue이면 decltype(e)
is T&
, 여기서 T
is 유형 e
;
— 그렇지 않으면 decltype(e)
유형입니다 e
.
decltype 지정자의 피연산자는 평가되지 않은 피연산자입니다 (Clause 5). [ 예:
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = 0; // type is const int&&
decltype(i) x2; // type is int
decltype(a->x) x3; // type is double
decltype((a->x)) x4 = x3; // type is const double&
—end example] [참고 : 관련 유형을 결정하는 규칙
decltype(auto)
은 7.1.6.4에 지정되어 있습니다. —end note]
에 대한 규칙 decltype(auto)
은 초기화 표현식의 RHS에서 추가 괄호에 대해 유사한 의미를 갖습니다. 다음은 C ++ FAQ 및 관련 Q & A의 예입니다.
decltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; } //A
decltype(auto) look_up_a_string_2() { auto str = lookup1(); return(str); } //B
첫 번째는 지역 변수에 대한 참조 인 string
두 번째를 반환하고 두 번째는 반환 string &
합니다 str
.
전 처리기 매크로 관련 오류 방지
적절한 C ++ 언어와 상호 작용할 때 전 처리기 매크로에는 미묘한 부분이 많이 있으며, 가장 일반적인 것은 아래에 나열되어 있습니다.
- 매크로 정의 내부 매크로 파라미터 괄호를 사용하여
#define TIMES(A, B) (A) * (B);
순서대로하여 불필요한 조작 우선 순위를 피하기 위해 (예로 TIMES(1 + 2, 2 + 1)
하는 9 산출하지만 주위의 괄호없이 6을 수득 할 (A)
및(B)
- 내부에 쉼표가있는 매크로 인수 주위에 괄호 사용 :
assert((std::is_same<int, int>::value));
그렇지 않으면 컴파일되지 않음
- 포함 된 헤더에서 매크로 확장을 방지하기 위해 함수 주위에 괄호 사용 :
(min)(a, b)
(ADL을 비활성화하는 원치 않는 부작용 포함 )
&(C::f)
의 피연산자&
는 여전히C::f
입니까?