質問
$ 10.2/4- [注:詳細なタイプの指定器(3.4.4)またはベース指定器(条項10)で名前を調べると、ネストされた名前を調べながら、すべての非タイプの宣言を無視します。 Name-specifier(3.4.3)は、関数、変数、および列挙宣言を無視します。
このセクションでは、名前の検索について説明しながら、この声明が非常に混乱していることがわかりました。
void S(){}
struct S{
S(){cout << 1;}
void f(){}
static const int x = 0;
};
int main(){
struct S *p = new struct ::S; // here ::S refers to type
p->::S::f();
S::x; // base specifier, ignores the function declaration 'S'
::S(); // nested name specifier, ignores the struct declaration 'S'.
delete p;
}
私の質問:
ルールについての私の理解は正しいですか?
なぜ
::S
自動的に新しい扱いを行うラインで、structを平均するためにS
, 、一方、最後の行::S
関数を意味しますS
グローバルネームスペースで。これは、ドキュメントのあいまいさを示していますか、それとも私がC ++標準ドキュメントから離れることはさらに別の日ですか?
解決
Q1:そう思う。
Q2:Cとの互換性a struct
Cでは、タグ名はまさにタグ名です。スタンドアロンでそれを使用できるようにするには、 typedef
. 。 C ++では、typedefは必要ありません。これにより、ライブが容易になります。しかし、C ++ルールは、関数名でタグ名を「過負荷」した既存のCヘッダーをインポートできる必要性によって複雑になっています。その標準的な例はUNIXです stat()
aを使用する関数 struct stat*
議論として。
Q3:標準的な読みは通常非常に困難です...あなたが読んでいるものを変更する場所が他にないことをすでに知っている必要があります。それをする方法を知っている人々が言語弁護士であることは奇妙ではありません...
他のヒント
あなたは2番目のコメントについて間違っています。の S::x
, 、 S
ネストされた名前指定子の名前です。標準が「ベーススペシファー」で言及するものは次のとおりです
namespace B { struct X { }; void X() }
struct A : B::X { }; // B::X is a base-specifier
あなたはこれについても正しくありません:
::S();
//ネストされた名前指定子、struct宣言「s」を無視します。
そのコードは関数を呼び出します ::S
ネストされた名前の指定機になります(ネストされた名前の指定機ではありません!)が、関数名とクラス/列挙の両方が同じ範囲で宣言されている場合、関数名がクラスまたは列挙名を非表示にするためです。
FWIW、次のコードはメインの2行目に等しく有効です
p->S::f();
重要なのはそれです S
a ::
, 、ルックアップが関数を無視するようにします。あなたが置くこと ::
前 S
あなたの場合には効果がありません。