2012-08-08 51 views
5

有沒有辦法在C++ 11中比較decltype的結果?decltype比較

換句話說,這是爲什麼代碼無效:

template<typename T, typename U> 
void func(T& t, U& u) { 
    if(decltype(t) == decltype(u)) { 
     // Some optimised version for this case 
    } else { 
     // A more general case for differing types 
    } 
} 

我知道,在某些情況下,這種特殊的問題可以通過模板偏特化來解決;我的問題是關於decltype s的比較。

編輯:在試圖通過SFINAE提供免費函數的默認過程中出現了這個問題。也許是一個更好的問題將是爲什麼這是無效的:

template<bool B> 
bool SomeFunction() { ... } 

template<typename T, typename U> 
bool SomeFunctionWrapper(T& t, U& u) { 
    SomeFunction<decltype(t) == decltype(u)>(); 
} 

因爲我已經發現了另一種解決方案(不涉及在所有模板),但是在一個階段我嘗試這樣做:

// If it exists, the free function is defined as 
// bool AFreeFunction(); 
typedef struct { char } undefined; 
template<typename T = void> 
undefined AFreeFunction(); 

template<bool B> 
bool AFreeFunctionWrapper_() { 
    return false; 
} 

template<> 
bool AFreeFunctionWrapper_<false>() { 
    return AFreeFunction(); 
} 

bool AFreeFunctionWrapper() { 
    return AFreeFunctionWrapper_<decltype(AFreeFunction()) == decltype(undefined)>(); 
} 

我最終得到了一個使用GCC 4.6的策略的變體,但後來發現默認模板參數不允許用於MSVC中的模板函數,即使在2012 RC中也是如此。因此,最終的解決方案如下所示:

class AFreeFunction { 
public: 
    operator bool() { return false; } 
}; 

如果函數被定義,它會被調用。如果不是,則將其解釋爲該類的構造函數,然後將其隱式轉換爲bool

+0

請注意,上面的自由函數形式不能用部分專業化來解決;它需要重新配置爲允許它的類模板。 – Tom 2012-08-08 09:34:10

+0

不,它不需要是類模板,它可以是一組簡單的*重載*函數模板。 – 2012-08-08 10:00:03

+0

@ n.m。好點子。 – Tom 2012-08-08 16:30:20

回答

8

您通常通過標籤分派來解決這個問題。此外,您已分別具有tu - T&U&的「聲明類型」。要比較類型是否相等,可以使用std::is_same。然而,重載決議已經解決了這個問題爲您:

template<class T> 
void f(T& v1, T& v2){ ... } // #1 

template<class T, class U> 
void f(T& t, U& u){ ... } // #2 

#1比#2更專業的如果兩個參數f是同一類型的。如果出於某種原因,堅持通過手動型對比解決這一點,這裏是它會怎樣看應用之前提到的幾點:

#include <type_traits> 

namespace detail{ 
template<class T, class U> 
void f(T& t, U& u, std::true_type){ ... } // #1 

template<class T, class U> 
void f(T& t, U& u, std::false_type){ ... } // #2 
} // detail:: 

template<class T, class U> 
void f(T& t, U& u){ 
    detail::f(t, u, std::is_same<T,U>()); // tag dispatching 
} 

std::is_same將從std::true_type派生如果兩個類型相同,並從std::false_type如果不。

+0

編譯器是否總是消除創建的真/假類型?我會在一個'bool'上專門設計一個模板,然後傳入這個類型。這樣,就不可能創建無用的類型。 – KitsuneYMG 2012-08-08 15:31:47

+0

我明白了,並認爲這可能是答案,但試圖爭取其他想法。實際的上下文是我試圖創建一個'template bool Function(){...}'和'template <> bool Function (){...}',然後將它初始化爲'bool b = Function ();'。我可能會將這個細節添加到問題中。 – Tom 2012-08-08 16:14:03

4

爲什麼它無效? decltype的結果就是一種類型。所以它是這樣說

if (int == int) 

其中語言顯然不允許。

您需要分離函數的兩個部分,並將專用部分放在專用類中的函數中,然後在那裏轉發呼叫。這是痛苦的。

或者,您可以使用typeid或運行時類型信息,如果您的實現正確地實現了它,雖然這會在程序運行時延遲一切(這可以減少優化)。

+0

也許我過分簡化了這個問題。我得到'if(int == int)'無效。我不太清楚爲什麼'some_template '無效。考慮類似於'some_template ' - 完全有效,'decltype'應該是'sizeof'的某種自然擴展。 – Tom 2012-08-08 16:29:19

+0

@Tom:'sizeof'返回一個*值*。 'decltype'「返回」一個*類型*。他們是不同的野獸.. – Mehrdad 2012-08-08 16:37:45

+1

不完全正確。 'sizeof'返回一個_constant_值,它使編譯器能夠在編譯時解析模板實例化。我的問題是爲什麼標準委員會不允許編譯時比較類型,因爲它們允許編譯時比較類型的大小。 – Tom 2012-08-09 10:06:28

3

你可以做到這一點使用SFINAE(std::enable_if):

template<typename T, typename U> 
typename std::enable_if<std::is_same<T, U>::value, void>::type func(T& t, U& u) { 
    std::cout << "same\n"; 
} 
template<typename T, typename U> 
typename std::enable_if<!std::is_same<T, U>::value, void>::type func(T& t, U& u) { 
    std::cout << "different\n"; 
} 

由於邁赫達德說,decltype(t)decltype(u)(分別T &U &)類型的,不是值,所以不能在價值的表達水平進行比較,但必須在元表達式(模板)級別進行比較。

+0

我明白這是如何工作的;只是想知道標準委員會是否有一個很好的理由不允許比較「decltype」的結果。看到編輯的問題,我想實現什麼;實際上比較是在模板參數上下文中發生的,並且與您的建議非常接近。雖然我沒有真正意識到'std :: enable_if',但沒有聽說過'std :: is_same'。 – Tom 2012-08-08 16:27:18

+0

@Tom'decltype'不是一個函數,它是一個運算符,所以它的「結果」不必像行爲一樣。 – ecatmur 2012-08-08 16:34:15

+0

我不確定我遵循那個推理。畢竟每個其他運營商的結果都像一個價值。 'sizeof'是一個非常緊密相關的運算符,它返回的行爲類似於一個值,但可以在編譯時與其他(常量)值進行比較,就像我(錯誤地)期望'decltype'要做的那樣。 – Tom 2012-08-09 10:10:51