2011-08-09 31 views
36

考慮從safe bool idiom以下摘錄:是否存在typedef絕對必要的情況?

typedef void (Testable::*bool_type)() const; 
operator bool_type() const; 

是否有可能宣佈轉換功能,而不typedef的?以下不編譯:

operator (void (Testable::*)() const)() const; 
+3

爲什麼你會聲明函數沒有typedef? –

+0

轉換爲安全布爾絕對必要嗎? –

+0

@Tad:在我的特殊情況下('可選'類模板)似乎很有用。 – fredoverflow

回答

9

啊,我只是想起了identity元功能。它可以編寫

operator typename identity<void (Testable::*)() const>::type() const; 

identity定義如下:

template <typename T> 
struct identity 
{ 
    typedef T type; 
}; 

你可以說,identity仍然採用了typedef,但這種方法是「好」對我來說足夠。

+0

我正要回答這個......身份是解決問題的好方法。 –

+0

@David:很遺憾,身份不是的標準C++ 0x。在這種情況下,我們可以使用'std :: decay',儘管... – fredoverflow

+0

這是我要做的更好的版本! – AJG85

2

我的分析說,不使用typedef是不可能的。編譯器將(看作第一個標記,並假定您已超載() operator,它不應該有任何參數(參數將在下一組括號中出現)。放置任何一組額外的括號也無濟於事 - 但實際上會混淆編譯器,從而導致更多的錯誤。

大多數STL代碼是對typedef initions頂部,我們應當/必須使用它們!

1

typedef不是宏你的第二個例子是不等同於第一。在第一種情況下,您的typedef正在定義一個仿函數,然後在仿函數類型的演員操作符中使用該類型。在第二個操作符使用錯誤的語法,因爲沒有操作符指定,因爲沒有類型。我不知道如何編寫它,但通常有一種方法。

除了在TMP中編寫人類可讀的代碼,Typedefs並不是真的必要,即使這樣它也取決於你是什麼樣的人。

由於我無法想出替代語法,因此在某些情況下可能需要typedefs。我只是想到另一個可能。假設你有沒有和專業化包含一個具有返回類型類似下面的靜態方法的模板:

template <typename T> 
struct WhateverHandler 
{ 
    typedef T rType; 
    static rType Whatever() { return rType(); } 
}; 

template <> 
struct WhateverHandler<std::string> 
{ 
    typedef std::string rType; 
    static rType Whatever() { return rType(); } 
}; 

我認爲在這種情況下,你需要的類型定義的順序,否則調用靜態方法不管專業化方法可能會混淆編譯器,因爲返回類型會有所不同,但它不會是一個適當的重載。使用

va_arg()宏時

在需要 typedef
template <typename T> 
struct WhateverUser 
{ 
    typename WhateverHandler<T>::rType DoWhatever() 
    { 
     return WhateverHandler<T>::template Whatever(); 
    } 
}; 
3

一種情況(無關你的問題)是。引用C99標準(7.15.1.1):

類型*的va_arg(va_list的AP,);

...

參數類型應指定使得 類型名稱的指針的一個對象的類型 已指定的類型可簡單地通過一個後綴'獲得*到

+1

還有另一種這樣的情況,即僞析構函數的調用 –

+0

也不允許使用''p->〜unsigned char()'(對於那些不知道僞析構函數是什麼或爲什麼需要那麼typedef在那裏) – MSalters

3

回答了「有沒有哪裏的類型定義是絕對必要的情況下?「從問題的標題,這裏是需要一個typedef的一個例子:

f(unsigned char()); // compiler error! 
typedef unsigned char Byte; 
f(Byte());   // fine! 

查看結果這裏:http://ideone.com/JPUra

+0

編譯器再次發生爭執!GCC失敗,VC成功。 – Ajay

+1

'f(identity :: type())'?;) – fredoverflow

+2

@FredOverflow看起來像它會工作,雖然技術上'type'是一個typedef。 :P – 2011-08-09 17:13:40

2

看來,語法在你的情況下,使用一個typedef需要一個轉換 - 功能-ID必須是形式的操作轉換型-ID轉換型-ID不能包含括號。所以,你必須轉換爲指針到函數類型時使用的typedef,或到一個指向成員函數的類型。

+0

「轉換類型標識不能包含圓括號。」你從哪裏得到? – TonyK

+0

@TonyK:從語法。它基本上可能是const/volatile基本類型或合格的id(type-specifier-seq),接着是零個或多個指針運算符(conversion-declarator-opt)。 –

+0

@n:我找到了一個方法:'template class C {}; class S {operator C <(99)> *(){return 0; }};' – TonyK

2

在C++ 11,你可以做這樣的(GCC 4.5.2):

operator decltype((void (Testable::*)() const)(0))() const ; 

我不是說這是很...

+0

等待,我只是在VC10中嘗試過它,它不起作用:(C2833 – fredoverflow

+0

你試過用'decltype(&Testable :: foo)'哪裏'foo'是一個具有相應簽名的成員方法? –

+0

@David:是的,是不行的:(C2833再次 – fredoverflow

1

我只是碰到這個問題跑,鏗鏘++:

foo.cpp:17:8: error: must use a typedef to declare a conversion to 'void (*(int))()' 

,並有覆蓋的身份<牛逼>功能的C++ 11 STL模板:

#include <type_traits> 
… 
struct foo { 
    void bar() const { } 
    operator std::common_type<void(foo::*)()const>::type() { return &foo::bar; } 
};