[解決済み] 演算子の優先順位以外で、余分な括弧が効果を発揮するのはどのような場合ですか?
質問
C++の括弧は、関数呼び出しや演算子の優先順位を上書きするための式のグループ化など、多くの場所で使用されています。 違法な余分な括弧は別として (関数呼び出しの引数リストなど) を除けば、C++ の一般的なルールとして 余分な括弧は決して損をしない :
5.1 一次式 [expr.prim] について
5.1.1 一般的なもの [expr.prim.general].
6 括弧で囲まれた式は、型と値が同じである一次式です。 が同じである一次式です。括弧の有無は が存在しても,その式がlvalueであるかどうかには影響しない。 括弧で囲まれた式は,囲んだ式と全く同じ文脈で使うことができる。 括弧で囲まれた式は,囲まれた式が使用できるのと全く同じ文脈で,同じ意味合いで使用することができます。 と同じ意味で使うことができます。 ただし、特に指定がない限り .
質問 : 基本的な演算子の優先順位を上書きする以外に、どのような状況で余分な括弧がC++プログラムの意味を変えるのでしょうか?
注意
: の制限を考えています。
ポインタ・トゥ・メンバ
構文を
&qualified-id
はスコープ外になるように括弧なしで
は構文を制限します。
というように、異なる意味を持つ二つの構文を許容するのではありません。同様に
プリプロセッサマクロ定義内の括弧は
も不要な演算子の優先順位から保護します。
どのように解決するのですか?
TL;DR
余分な括弧は、以下の文脈でC++プログラムの意味を変えます。
- 引数依存の名前検索を防止する
- リストコンテキストでカンマ演算子を有効にする
- 厄介な解析の曖昧さ解消
-
での参照性の推論
decltype
表現 - プリプロセッサーのマクロエラーの防止
引数依存の名前ルックアップの防止
規格の附属書Aで詳しく説明されているように
post-fix expression
という形式の
(expression)
は
primary expression
ではありませんが
id-expression
でもなく、したがって
unqualified-id
. これは、引数依存の名前検索が、以下の形式の関数呼び出しで防がれることを意味します。
(fun)(arg)
という形式の関数呼び出しでは、従来の形式である
fun(arg)
.
3.4.2 引数依存の名前検索 [basic.lookup.argdep].
1 いつ が、関数呼び出しの後置表現(5.2.2)が 非限定ID である場合、通常の非限定検索 (3.4.1) では考慮されない他の名前空間が検索されることがあります。 は、通常の非限定検索 (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);
<ブロッククオート
は3つの引数を持ち、そのうちの2番目の引数は値5です。 ]
むつかしい構文の曖昧さ解消
C 言語とその難解な関数宣言構文との後方互換性は、vexing parses として知られる驚くべき解析のあいまいさにつながる可能性があります。本質的には 宣言としてパースできるものはすべて宣言としてパースされます。 として解析されます。
6.8 曖昧さ解消 [stmt.ambig] (英語)
1 式-ステートメントを含む文法には曖昧さがある と宣言 : 関数型の明示的な型変換(5.2.3)を左端の部分式とする式文は 明示的な型変換 (5.2.3) を左端の部分式として持つ式文は、最初の宣言子が開始される宣言と区別がつかないことがあります。 最初の宣言子が(.)で始まる宣言と見分けがつかない。 で始まる宣言と区別がつきません。 このような場合、ステートメントは宣言である .
8.2 曖昧さの解消 [dcl.ambig.res]
1 6.8で述べた関数型キャストと宣言の類似性から生じる曖昧さは、関数型キャストの文脈でも生じます。 と宣言の類似性から生じる曖昧さは、6.8で述べた 宣言の . この文脈では、パラメータを囲む冗長な括弧を持つ関数 パラメータを囲む冗長な括弧を持つ関数宣言と、関数スタイルのキャストを持つオブジェクト宣言のどちらを選ぶかです。 と、初期化子として関数型キャストを使ったオブジェクト宣言のどちらかを選択することになります。 のどちらかを選ぶことになります。6.8で述べた曖昧さと同じように、その解決策は の解決策は である可能性のあるすべての構成要素を 宣言とみなすことです。 . [注意: 宣言は、非関数型キャストや、宣言であることを示す = で明示的に区別することができます。 宣言は、非関数型キャスト、=による初期化、冗長な括弧の削除によって明確に区別されます。 による初期化、あるいはパラメータ名の周りの冗長な括弧を削除することで、宣言の曖昧さをなくすことができます。 パラメータ名の周りにある冗長な括弧を削除することです。-終了メモ ]。[ 例
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
}
<ブロッククオート
-終了例 ]。
この例として有名なのが 最も厄介なパース の項目 6 で Scott Meyers によって広められた名前です。 効果的なSTL の本があります。
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>
. この
関数dataは2つのパラメータをとります。
-
最初のパラメータは
dataFile
. このパラメータはistream_iterator<int>
. である。 を囲む括弧はdataFile
は余計なので無視されます。 -
第2パラメータは名前を持ちません。その型は、何も取らず
を返す関数へのポインタです。
istream_iterator<int>
.
最初の関数引数の周りに余分な括弧を置くと(2番目の引数の周りの括弧は違法です)、曖昧さが解消されます。
list<int> data((istream_iterator<int>(dataFile)), // note new parens
istream_iterator<int>()); // around first argument
// to list's constructor
C++11 には brace-initializer 構文があり、多くのコンテキストでこのような解析の問題を回避することができます。
での参照性の推論
decltype
の表現で参照可能である。
とは対照的に
auto
型の推論を行います。
decltype
は参照性(lvalueとrvalueの参照)を推論することを許可します。ルールでは
decltype(e)
と
decltype((e))
という表現があります。
7.1.6.2 単純な型指定子 [dcl.type.simple]
4 式の場合
e
, で示される型はdecltype(e)
は次のように定義されます。 は次のように定義される。- もし
e
が親展されていないid-expressionまたは 親展されていないクラスメンバーアクセス(5.2.5)である場合。decltype(e)
は型 によって名付けられたエンティティのe
. そのような実体がない場合、あるいはe
が がオーバーロードされた関数のセットを指定した場合、 プログラムは不正な形式となります。- それ以外の場合は もし
e
がxvalueであればdecltype(e)
はT&&
であり、ここでT
のタイプはe
;- それ以外の場合は
e
がl値である場合。decltype(e)
はT&
であり、ここでT
は のe
;- さもなければ
decltype(e)
の型はe
.のオペランドは評価されません。 decltype指定子のオペランドは評価されないオペランドです(条項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&
<ブロッククオート
-終了例 ]。[注意:このルールでは
decltype(auto)
を含む型を決定するルールは,7.1.6.4に規定されている。]
のルールは
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
1つ目の戻り値は
string
を返し、2つ目は
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 も無効になります)
関連
-
[解決済み] テスト
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++
-
[解決済み] mutable' キーワードには、const 関数で変数を変更できるようにする以外の目的があるのでしょうか?
-
[解決済み】Scalaにおける中括弧と括弧の正式な違い、また、どのような場合に使用すべきなのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】coutはstdのメンバではない
-
[解決済み】getline()が何らかの入力の後に使用されると動作しない 【重複あり
-
[解決済み】C-stringを使用すると警告が表示される。"ローカル変数に関連するスタックメモリのアドレスが返される"
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない
-
[解決済み] decltype(auto)の使い方にはどのようなものがありますか?
-
[解決済み] 値の初期化を試みたが、関数宣言と解釈された。A a(()); で解決しないのはなぜか?