2015-01-20 31 views
13

clang不編譯下面的第三個調用typeid(請參閱live example)。但是我在§5.2.8中看不到任何不允許的東西,特別是當我們認爲表達式B::f不是多態類類型的glvalue時(參見段落3)。此外,根據該段,表達式B::f是一個未評估的操作數,因此,調用typeid(B::f)應該編譯。需要注意的是GCC不編譯任何的話費給typeid如下:typeid不適用於非靜態成員函數

#include <iostream> 
#include <typeinfo> 

struct A{ int i; }; 
struct B{ int i; void f(); }; 

int main() 
{ 
    std::cout << typeid(A::i).name() << '\n'; 
    std::cout << typeid(B::i).name() << '\n'; 
    std::cout << typeid(B::f).name() << '\n'; 
} 
+0

@Yakk我用g ++進行測試,並確認沒有三個compi le,然後編輯這個問題來解決雙重否定。 – 2015-01-20 19:50:15

+0

將'&'放入它們中會導致所有這些工作都在兩個編譯器上工作,例如, '&B :: i'。但是,我想這不是重點!爲什麼他們沒有'&'工作? – 2015-01-20 19:55:44

+0

@MarkB感謝您的糾正。正如你所看到的,我沒有完全掌握英語。 – Belloc 2015-01-20 20:14:08

回答

11

至於我可以告訴clang是正確的,使用非靜態成員只在一個未計算的情況下有效的,如果它是一個數據成員。因此,對於前兩種情況,gcc看起來不正確,但在sizeofdecltype的情況下,gcc也可以正常工作,這些操作數也沒有被評估。

draft C++11 standard5.1.1[expr.prim.general]

一個ID表達式表示一類的非靜態數據成員或非靜態 成員函數只能是使用:

,幷包括以下子彈:

如果該id表達式表示一個非靜態數據成員,並且它在未被評估的操作數中出現 。 [實施例:

struct S { 
    int m; 
}; 
int i = sizeof(S::m); // OK 
int j = sizeof(S::m + 42); // OK 

末端示例]

子彈的其餘部分不適用,它們如下:

  • 作爲的一部分類成員訪問(5.2.5),其中對象表達是指成員的類或從 類派生的類,或
  • 以在MEM-初始化指針構件(5.3.1)或
  • 用於該類或用於從類派生的類的構造函數( 12.6.2),或
  • 在大括號或相等的初始值設定爲該類別或從該類(12.6.2)派生的類的非靜態數據成員,或者

我們知道,操作數是從5.2.8部分未評估,其中說:

當typeid應用於除多態類類型的glvalue以外的表達式時,[...]該表達式是一個未評估的操作數 (第5章)。

我們可以從語法,一個ID表達或者是一個不合格-ID合格-ID看到:

id-expression: 
    unqualified-id 
    qualified-id 

更新

提起一個gcc bug report: typeid does not allow an id-expression that denotes a non-static data member

+1

Darn - 幾乎完成了幾乎相同的回答,但是在發佈時正在從5.1.1格式化'primary-expression'的語法... – 2015-01-20 19:59:35

1

typeid(A::i).name()不完全做我認爲會做的事。我期望它是一個指向成員的指針,但它實際上只是一個int

看到這一點,運行此代碼:

#include <iostream> 
struct A{ int i; }; 
struct B{ int i; void f(void); }; 

template<typename T> 
void what_is_my_type() { 
    std:: cout << __PRETTY_FUNCTION__ << std:: endl; 
} 

int main() 
{ 
    what_is_my_type<decltype(&A::i)>(); // "void what_is_my_type() [T = int A::*]" 
    what_is_my_type<decltype(&B::i)>(); // "void what_is_my_type() [T = int B::*]" 
    what_is_my_type<decltype(&B::f)>(); // "void what_is_my_type() [T = void (B::*)()]" 

    what_is_my_type<decltype(A::i)>(); // "void what_is_my_type() [T = int]" 
    what_is_my_type<decltype(B::i)>(); // "void what_is_my_type() [T = int]" 
    // what_is_my_type<decltype(B::f)>();  // doesn't compile 

} 

我已經把輸出註釋每次通話後。

前三個調用按預期工作 - 所有三個工作和類型信息都包含結構類型(AB)以及成員類型。

儘管最後三個不同。最後一個甚至沒有編譯,前兩個只是打印int。我認爲這是線索問題。這是可能的,給予特定AB,採取特定成員的地址:

A a; 
int * x = &(a.i); 
*x = 32; 

可能(甚至是有意義的?)要做到這一點:

B b; 
??? y = &(a.f); // what does this even mean? 

最後,要強調這不是關於指針,請考慮這一點:

A a; 
B b; 
int x = a.i; 
int y = b.i; 
??? z = b.f; // what would this mean? What's its type? 
相關問題