2016-10-02 107 views
3

考慮這個例子:檢查類型被定義

#include <iostream> 
#include <type_traits> 

template <class, class = void> 
struct is_defined : std::false_type 
{ }; 

template <class T> 
struct is_defined<T, 
    std::enable_if_t<std::is_object<T>::value && 
        !std::is_pointer<T>::value 
     > 
    > : std::true_type 
{ 
private: 
    static const T test; //try to create incomplete type member 
}; 

struct defined { }; 

struct forward_declared; 

int main() 
{ 
    std::cout << std::boolalpha 
       << is_defined<defined>::value << std::endl 
       << is_defined<forward_declared>::value << std::endl; 
} 

輸出是true兩者。我想如果我嘗試使不完整類型的成員struct成員,那麼這個模板專門化將從超載設置中丟棄。但事實並非如此。刪除static const會導致不完整的編譯時錯誤。這種方法有什麼問題,如果可能的話,怎麼能實現呢?

+0

'is_object'並不意味着'is_complete'。 –

+0

@ n.m。這只是爲了不允許檢查參考。我可以使用'std :: is_reference'來代替,但這並沒有太大的不同。 – xinaiz

+0

好的我看到你正在試圖聲明一個靜態的東西去除不完整的類型。無論如何,你需要使用ODR來使用靜態的東西。 –

回答

6

試試這個:

template <class T> 
struct is_defined<T, 
    std::enable_if_t<std::is_object<T>::value && 
        !std::is_pointer<T>::value && 
        (sizeof(T) > 0) 
     > 
    > : std::true_type 
{ 
}; 
+0

哇,這是快速的:)你能解釋爲什麼我們可以通過嘗試在不完整類型上應用'sizeof'來放棄超載,但是我們不能通過使'T'成員來做到這一點? – xinaiz

+0

@BlackMoses這只是你的普通的SFINAE。 'sizeof'不適用於不完整的類型,所以替換將失敗。 –

1

關於問題「什麼是不對的做法......」 當我們有靜態常量T檢驗;它不是is_defined < ...>類的一部分,我們實際上必須定義靜態成員is_defined < ...> ::測試別的地方,只有在那個「其他」地方,我們需要T是完整類型。 is_defined < ...>僅僅因爲靜態成員大小對is_defined < ...>大小沒有影響才編譯類。

去除靜態const會導致T test;成爲is_defined < ...>(並且影響is_defined < ...> size)的成員,因此T必須是完整類型才能具有已知大小。

UPD注:在聲明類構件在模板特它不是由SFINAE丟棄僅僅因爲這是也不是「參數替換」,也不是一種「SFINAE表達」的情況下(以及不是函數超載!)。相反,它是某種「SFINAE現場聲明」 - 而不是標準中所述的「替代失敗時不是錯誤」。

+0

感謝您的解釋。但是,當這種不完整類型是成員時,爲什麼模板專門化不會從過載中丟棄?相反,它會導致錯誤。 – xinaiz

+0

在模板特化中聲明類成員的情況下,它不會被SFINAE丟棄,因爲這不是「參數替換」,也不是「SFINAE表達式」(也不是被重載的函數!)。相反,它是某種「SFINAE現場聲明」 - 而不是標準中所述的「替代失敗時不是錯誤」。 –

1

一般來說,在這種情況下,您可以使用您的sfinae表達式中的某些不接受不完整類型的運算符。
舉個例子,你可以使用typeid

#include <iostream> 
#include <type_traits> 
#include <utility> 

template<typename T, typename = void> 
constexpr bool is_defined = false; 

template<typename T> 
constexpr bool is_defined<T, decltype(typeid(T), void())> = true; 

struct defined { }; 
struct forward_declared; 

int main() 
{ 
    std::cout << std::boolalpha 
       << is_defined<defined> << std::endl 
       << is_defined<forward_declared> << std::endl; 
} 

正如其他人所提到的,另一個有效運營商sizeof